ordering-ui-react-native 0.15.3 → 0.15.6

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.15.3",
3
+ "version": "0.15.6",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -48,6 +48,8 @@
48
48
  "@react-navigation/material-bottom-tabs": "^5.3.14",
49
49
  "@react-navigation/native": "^5.7.6",
50
50
  "@react-navigation/stack": "^5.9.3",
51
+ "@segment/analytics-react-native": "^2.1.11",
52
+ "@segment/sovran-react-native": "^0.2.6",
51
53
  "@sentry/react-native": "^2.6.0",
52
54
  "@stripe/stripe-react-native": "^0.2.0",
53
55
  "@types/react-native-loading-spinner-overlay": "^0.5.2",
@@ -1,5 +1,6 @@
1
1
  import { AddressForm } from './src/components/AddressForm';
2
2
  import { AddressDetails } from './src/components/AddressDetails';
3
+ import { AnalyticsSegment } from './src/components/AnalyticsSegment';
3
4
  import { Home } from './src/components/Home';
4
5
  import { LoginForm } from './src/components/LoginForm';
5
6
  import { SignupForm } from './src/components/SignupForm';
@@ -67,6 +68,7 @@ import {
67
68
  export {
68
69
  AddressForm,
69
70
  AddressDetails,
71
+ AnalyticsSegment,
70
72
  Home as HomeView,
71
73
  SignupForm,
72
74
  LoginForm,
@@ -0,0 +1,127 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { createClient, AnalyticsProvider } from '@segment/analytics-react-native';
3
+ import { useEvent, useConfig } from 'ordering-components/native';
4
+
5
+ export const AnalyticsSegment = (props: any) => {
6
+ const { children } = props
7
+
8
+ const [events] = useEvent()
9
+ const [configState] = useConfig()
10
+ const [segmentClient, setSegmentClient] = useState<any>({})
11
+
12
+ const handleClickProduct = (product: any) => {
13
+ segmentClient.track('Product Clicked', {
14
+ id: product.id,
15
+ name: product.name,
16
+ category: product.category_id,
17
+ price: product.price
18
+ })
19
+ }
20
+
21
+ const handleProductAdded = (product: any) => {
22
+ segmentClient.track('Product Added', {
23
+ id: product.id,
24
+ name: product.name,
25
+ category: product.category_id,
26
+ price: product.price,
27
+ quantity: product.quantity
28
+ })
29
+ }
30
+
31
+ const handleProductRemoved = (product: any) => {
32
+ segmentClient.track('Product Removed', {
33
+ id: product.id,
34
+ name: product.name,
35
+ category: product.category_id,
36
+ price: product.price,
37
+ quantity: product.quantity
38
+ })
39
+ }
40
+
41
+ const handleOrderPlaced = (order: any) => {
42
+ segmentClient.track('Order Placed', {
43
+ id: order.id,
44
+ affiliation: order.business?.name,
45
+ revenue: order.total,
46
+ tax: order.tax_total,
47
+ shipping: order.delivery_zone_price
48
+ })
49
+ segmentClient.track('Payment Info Entered', {
50
+ order: order.id,
51
+ business: order.business?.name,
52
+ business_id: order.business_id,
53
+ total: order.total,
54
+ tax: order.tax_total,
55
+ delivery: order.delivery_zone_price,
56
+ paymethod: order.paymethod
57
+ })
58
+ }
59
+
60
+ const handleUpdateOrder = (order: any) => {
61
+ segmentClient.track('Order Updated', {
62
+ id: order.id,
63
+ affiliation: order.business?.name,
64
+ revenue: order.total,
65
+ tax: order.tax_total,
66
+ shipping: order.delivery_zone_price
67
+ })
68
+ }
69
+
70
+ const handleAddOrder = (order: any) => {
71
+ segmentClient.track('Order Added', {
72
+ id: order.id,
73
+ affiliation: order.business?.name,
74
+ revenue: order.total,
75
+ tax: order.tax_total,
76
+ shipping: order.delivery_zone_price
77
+ })
78
+ }
79
+
80
+ const handleLogin = (data: any) => {
81
+ segmentClient.identify(data.id, {
82
+ email: data.email,
83
+ name: data.name
84
+ })
85
+ }
86
+
87
+ useEffect(() => {
88
+ if (segmentClient?.config?.writeKey) {
89
+ events.on('product_clicked', handleClickProduct)
90
+ events.on('userLogin', handleLogin)
91
+ events.on('product_added', handleProductAdded)
92
+ events.on('order_placed', handleOrderPlaced)
93
+ events.on('order_updated', handleUpdateOrder)
94
+ events.on('order_added', handleAddOrder)
95
+ events.on('cart_product_removed', handleProductRemoved)
96
+ }
97
+ return () => {
98
+ if (segmentClient?.config?.writeKey) {
99
+ events.off('product_clicked', handleClickProduct)
100
+ events.off('userLogin', handleLogin)
101
+ events.off('product_added', handleProductAdded)
102
+ events.off('order_placed', handleOrderPlaced)
103
+ events.off('order_updated', handleUpdateOrder)
104
+ events.off('order_added', handleAddOrder)
105
+ events.off('cart_product_removed', handleProductRemoved)
106
+ }
107
+ }
108
+ }, [segmentClient])
109
+
110
+ useEffect(() => {
111
+ if (configState?.configs?.segment_track_id?.value) {
112
+ const _segmentClient: any = createClient({
113
+ writeKey: configState?.configs?.segment_track_id?.value
114
+ });
115
+ setSegmentClient(_segmentClient)
116
+ }
117
+ }, [configState])
118
+
119
+ return (
120
+ <>
121
+ <AnalyticsProvider client={segmentClient}>
122
+ {children}
123
+ </AnalyticsProvider>
124
+ </>
125
+
126
+ )
127
+ }
@@ -29,7 +29,7 @@ const types = ['food', 'laundry', 'alcohol', 'groceries'];
29
29
  export const BusinessBasicInformation = (
30
30
  props: BusinessBasicInformationParams,
31
31
  ) => {
32
- const { navigation, businessState, isBusinessInfoShow, logo, header } = props;
32
+ const { navigation, businessState, isBusinessInfoShow, logo, header, isPreOrder } = props;
33
33
  const { business, loading } = businessState;
34
34
 
35
35
  const theme = useTheme();
@@ -181,12 +181,16 @@ export const BusinessBasicInformation = (
181
181
  <WrapReviews>
182
182
  {!isBusinessInfoShow && (
183
183
  <>
184
- <TouchableOpacity onPress={() => navigation.navigate('BusinessPreorder', { business: businessState?.business, handleBusinessClick: () => navigation?.goBack() })}>
185
- <OText color={theme.colors.textSecondary} style={{ textDecorationLine: 'underline' }}>
186
- {t('PRE_ORDER', 'Preorder')}
187
- </OText>
188
- </TouchableOpacity>
189
- <OText size={12} color={theme.colors.textSecondary}>{' \u2022 '}</OText>
184
+ { isPreOrder && (
185
+ <>
186
+ <TouchableOpacity onPress={() => navigation.navigate('BusinessPreorder', { business: businessState?.business, handleBusinessClick: () => navigation?.goBack() })}>
187
+ <OText color={theme.colors.textSecondary} style={{ textDecorationLine: 'underline' }}>
188
+ {t('PRE_ORDER', 'Preorder')}
189
+ </OText>
190
+ </TouchableOpacity>
191
+ <OText size={12} color={theme.colors.textSecondary}>{' \u2022 '}</OText>
192
+ </>
193
+ )}
190
194
  <TouchableOpacity onPress={() => setOpenBusinessReviews(true)}>
191
195
  <OText color={theme.colors.textSecondary} style={{ textDecorationLine: 'underline' }}>
192
196
  {t('REVIEWS', 'Reviews')}
@@ -262,4 +266,4 @@ const styles = StyleSheet.create({
262
266
  zIndex: 100,
263
267
  left: 40
264
268
  },
265
- });
269
+ });
@@ -8,7 +8,8 @@ import {
8
8
  useSession,
9
9
  useUtils,
10
10
  ToastType,
11
- useToast
11
+ useToast,
12
+ useConfig
12
13
  } from 'ordering-components/native'
13
14
  import { OButton, OIcon, OModal, OText } from '../shared'
14
15
  import { BusinessBasicInformation } from '../BusinessBasicInformation'
@@ -52,7 +53,8 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
52
53
  const [orderState] = useOrder()
53
54
  const [{ parsePrice }] = useUtils()
54
55
  const [, { showToast }] = useToast()
55
-
56
+ const [{ configs }] = useConfig()
57
+ const isPreOrder = configs?.preorder_status_enabled?.value === '1'
56
58
  const styles = StyleSheet.create({
57
59
  mainContainer: {
58
60
  flex: 1,
@@ -231,6 +233,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
231
233
  openBusinessInformation={openBusinessInformation}
232
234
  header={header}
233
235
  logo={logo}
236
+ isPreOrder={isPreOrder}
234
237
  />
235
238
  <View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100 }} />
236
239
  {!loading && business?.id && (
@@ -134,6 +134,7 @@ const CheckoutUI = (props: any) => {
134
134
 
135
135
 
136
136
  const isWalletEnabled = configs?.wallet_enabled?.value === '1' && (configs?.wallet_cash_enabled?.value === '1' || configs?.wallet_credit_point_enabled?.value === '1')
137
+ const isPreOrder = configs?.preorder_status_enabled?.value === '1'
137
138
 
138
139
  const driverTipsOptions = typeof configs?.driver_tip_options?.value === 'string'
139
140
  ? JSON.parse(configs?.driver_tip_options?.value) || []
@@ -149,6 +150,12 @@ const CheckoutUI = (props: any) => {
149
150
  }
150
151
  })
151
152
 
153
+ const handleMomentClick = () => {
154
+ if (isPreOrder) {
155
+ navigation.navigate('MomentOption')
156
+ }
157
+ }
158
+
152
159
  const handlePlaceOrder = () => {
153
160
  if (!userErrors.length) {
154
161
  handlerClickPlaceOrder && handlerClickPlaceOrder()
@@ -260,19 +267,21 @@ const CheckoutUI = (props: any) => {
260
267
  />
261
268
  </CHMomentWrapper>
262
269
  <CHMomentWrapper
263
- onPress={() => navigation.navigate('MomentOption')}
264
- disabled={loading}
270
+ onPress={() => handleMomentClick()}
271
+ disabled={loading}
265
272
  >
266
273
  <OText size={12} numberOfLines={1} ellipsizeMode='tail' color={theme.colors.textSecondary}>
267
274
  {options?.moment
268
275
  ? parseDate(options?.moment, { outputFormat: configs?.dates_moment_format?.value })
269
276
  : t('ASAP_ABBREVIATION', 'ASAP')}
270
277
  </OText>
271
- <OIcon
272
- src={theme.images.general.arrow_down}
273
- width={10}
274
- style={{ marginStart: 8 }}
275
- />
278
+ { isPreOrder && (
279
+ <OIcon
280
+ src={theme.images.general.arrow_down}
281
+ width={10}
282
+ style={{ marginStart: 8 }}
283
+ />
284
+ )}
276
285
  </CHMomentWrapper>
277
286
  </ChHeader>
278
287
  <View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100, marginTop: 18, marginHorizontal: -40 }} />
@@ -37,7 +37,8 @@ import {
37
37
  ExtraOptionWrap,
38
38
  WeightUnitSwitch,
39
39
  WeightUnitItem,
40
- TopActions
40
+ TopActions,
41
+ ProductSummary
41
42
  } from './styles';
42
43
  import { OButton, OIcon, OInput, OText } from '../shared';
43
44
  import { ScrollView } from 'react-native-gesture-handler';
@@ -170,8 +171,11 @@ export const ProductOptionsUI = (props: any) => {
170
171
  pieces: true
171
172
  })
172
173
  const [pricePerWeightUnit, setPricePerWeightUnit] = useState<any>(null)
173
-
174
+ const scrollViewRef = useRef<any>(null);
174
175
  const swiperRef: any = useRef(null)
176
+ const [optionLayout, setOptionLayout] = useState<any>({})
177
+ const [headerRefHeight, setHeaderRefHeight] = useState(0)
178
+ const [summaryRefHeight, setSummaryRefHeight] = useState(0)
175
179
 
176
180
  const isError = (id: number) => {
177
181
  let bgColor = theme.colors.white;
@@ -253,6 +257,28 @@ export const ProductOptionsUI = (props: any) => {
253
257
  handleChangeProductCartQuantity(quantity)
254
258
  }
255
259
 
260
+ const scrollDown = (id: any) => {
261
+ const isErrors = Object.values(errors).length > 0
262
+ if (!isErrors) {
263
+ return
264
+ }
265
+ const targetOptionId = Object.getOwnPropertyNames(errors).filter(item => !item.includes(id))[0]
266
+ const targetY = optionLayout[targetOptionId]?.y
267
+ if (targetY) {
268
+ scrollViewRef.current.scrollTo({
269
+ y: targetY + headerRefHeight + summaryRefHeight,
270
+ animated: true
271
+ })
272
+ }
273
+ }
274
+
275
+ const handleOnLayout = (event: any, optionId: any) => {
276
+ const _optionLayout = { ...optionLayout }
277
+ const optionKey = 'id:' + optionId
278
+ _optionLayout[optionKey] = { y: event.nativeEvent.layout?.y }
279
+ setOptionLayout(_optionLayout)
280
+ }
281
+
256
282
  useEffect(() => {
257
283
  const imageList: any = []
258
284
  const videoList: any = []
@@ -343,10 +369,10 @@ export const ProductOptionsUI = (props: any) => {
343
369
  <OIcon src={theme.images.general.arrow_left} width={15} />
344
370
  </TopActions>
345
371
  </TopHeader>
346
- <ScrollView>
372
+ <ScrollView ref={scrollViewRef}>
347
373
  {!error && (
348
374
  <View style={{ paddingBottom: 80 }}>
349
- <WrapHeader>
375
+ <WrapHeader onLayout={(event: any) => setHeaderRefHeight(event.nativeEvent.layout?.height)}>
350
376
  {loading && !product ? (
351
377
  <View style={styles.productHeaderSkeleton}>
352
378
  <Placeholder Animation={Fade}>
@@ -470,96 +496,98 @@ export const ProductOptionsUI = (props: any) => {
470
496
  )}
471
497
  </WrapHeader>
472
498
  <WrapContent>
473
- <ProductTitle>
474
- {loading && !product ? (
475
- <Placeholder Animation={Fade}>
476
- <View
477
- style={{
478
- flexDirection: 'row',
479
- justifyContent: 'space-between',
480
- }}>
481
- <PlaceholderLine width={40} height={20} />
482
- <PlaceholderLine width={30} height={20} />
483
- </View>
484
- </Placeholder>
485
- ) : (
486
- <>
487
- <View style={{ flexDirection: 'row' }}>
488
- <OText
489
- size={20}
490
- lineHeight={30}
491
- weight={'600'}
492
- style={{ flex: 1, marginBottom: 10 }}>
493
- {product?.name || productCart.name}
494
- </OText>
495
- {!!product?.calories && (
496
- <OText size={16} style={{ color: '#808080' }}>{product?.calories} cal
499
+ <ProductSummary onLayout={(event: any) => setSummaryRefHeight(event.nativeEvent.layout?.height)}>
500
+ <ProductTitle>
501
+ {loading && !product ? (
502
+ <Placeholder Animation={Fade}>
503
+ <View
504
+ style={{
505
+ flexDirection: 'row',
506
+ justifyContent: 'space-between',
507
+ }}>
508
+ <PlaceholderLine width={40} height={20} />
509
+ <PlaceholderLine width={30} height={20} />
510
+ </View>
511
+ </Placeholder>
512
+ ) : (
513
+ <>
514
+ <View style={{ flexDirection: 'row' }}>
515
+ <OText
516
+ size={20}
517
+ lineHeight={30}
518
+ weight={'600'}
519
+ style={{ flex: 1, marginBottom: 10 }}>
520
+ {product?.name || productCart.name}
497
521
  </OText>
498
- )}
499
- </View>
500
- {((!!product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (!!product?.estimated_person)) && (
501
- <OText size={14} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={'#909BA9'} mBottom={7}>
502
- {
503
- ((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (productCart?.sku && productCart?.sku !== '-1' && productCart?.sku !== '1'))
504
- && <>{t('SKU', 'Sku')}{' '}{product?.sku || productCart?.sku}</>
505
- }
506
- {product?.sku && product?.sku !== '-1' && product?.sku !== '1' && product?.estimated_person && (
507
- <>&nbsp;&#183;&nbsp;</>
508
- )}
509
- {product?.estimated_person
510
- && <>{product?.estimated_person}{' '}{t('ESTIMATED_PERSONS', 'persons')}</>
511
- }
512
- </OText>
513
- )}
514
- {isHaveWeight ? (
515
- <OText size={16} lineHeight={24} color={theme.colors.primary}>{parsePrice(pricePerWeightUnit)} / {product?.weight_unit}</OText>
516
- ) : (
517
- <View style={{ flexDirection: 'row', marginBottom: 10 }}>
518
- <OText size={16} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={theme.colors.primary}>{productCart.price ? parsePrice(productCart.price) : ''}</OText>
519
- {product?.offer_price !== null && product?.in_offer && (
520
- <OText style={{
521
- fontSize: 14,
522
- color: '#808080',
523
- textDecorationLine: 'line-through',
524
- marginLeft: 7,
525
- marginRight: 7
526
- }}>{product?.offer_price ? parsePrice(product?.offer_price) : ''}</OText>
522
+ {!!product?.calories && (
523
+ <OText size={16} style={{ color: '#808080' }}>{product?.calories} cal
524
+ </OText>
527
525
  )}
528
526
  </View>
529
- )}
530
- </>
531
- )}
532
- </ProductTitle>
533
- <ProductDescription>
534
- <OText color={theme.colors.textSecondary} size={12} lineHeight={18}>
535
- {product?.description || productCart?.description}
536
- </OText>
537
- </ProductDescription>
538
- <ScrollView
539
- horizontal
540
- showsHorizontalScrollIndicator={false}
541
- contentContainerStyle={{ paddingBottom: 30 }}
542
- >
543
- {product?.tags?.map((tag: any) => (
544
- <View
545
- key={tag.id}
546
- style={styles.productTagWrapper}
547
- >
548
- {!!tag?.image ? (
549
- <OIcon
550
- url={optimizeImage(tag?.image, 'h_40,c_limit')}
551
- style={styles.productTagImageStyle}
552
- />
553
- ) : (
554
- <OIcon
555
- src={theme.images?.dummies?.product}
556
- style={styles.productTagImageStyle}
557
- />
558
- )}
559
- <OText color={theme.colors.textSecondary} size={12} style={styles.productTagNameStyle}>{tag.name}</OText>
560
- </View>
561
- ))}
562
- </ScrollView>
527
+ {((!!product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (!!product?.estimated_person)) && (
528
+ <OText size={14} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={'#909BA9'} mBottom={7}>
529
+ {
530
+ ((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (productCart?.sku && productCart?.sku !== '-1' && productCart?.sku !== '1'))
531
+ && <>{t('SKU', 'Sku')}{' '}{product?.sku || productCart?.sku}</>
532
+ }
533
+ {product?.sku && product?.sku !== '-1' && product?.sku !== '1' && product?.estimated_person && (
534
+ <>&nbsp;&#183;&nbsp;</>
535
+ )}
536
+ {product?.estimated_person
537
+ && <>{product?.estimated_person}{' '}{t('ESTIMATED_PERSONS', 'persons')}</>
538
+ }
539
+ </OText>
540
+ )}
541
+ {isHaveWeight ? (
542
+ <OText size={16} lineHeight={24} color={theme.colors.primary}>{parsePrice(pricePerWeightUnit)} / {product?.weight_unit}</OText>
543
+ ) : (
544
+ <View style={{ flexDirection: 'row', marginBottom: 10 }}>
545
+ <OText size={16} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={theme.colors.primary}>{productCart.price ? parsePrice(productCart.price) : ''}</OText>
546
+ {product?.offer_price !== null && product?.in_offer && (
547
+ <OText style={{
548
+ fontSize: 14,
549
+ color: '#808080',
550
+ textDecorationLine: 'line-through',
551
+ marginLeft: 7,
552
+ marginRight: 7
553
+ }}>{product?.offer_price ? parsePrice(product?.offer_price) : ''}</OText>
554
+ )}
555
+ </View>
556
+ )}
557
+ </>
558
+ )}
559
+ </ProductTitle>
560
+ <ProductDescription>
561
+ <OText color={theme.colors.textSecondary} size={12} lineHeight={18}>
562
+ {product?.description || productCart?.description}
563
+ </OText>
564
+ </ProductDescription>
565
+ <ScrollView
566
+ horizontal
567
+ showsHorizontalScrollIndicator={false}
568
+ contentContainerStyle={{ paddingBottom: 30 }}
569
+ >
570
+ {product?.tags?.map((tag: any) => (
571
+ <View
572
+ key={tag.id}
573
+ style={styles.productTagWrapper}
574
+ >
575
+ {!!tag?.image ? (
576
+ <OIcon
577
+ url={optimizeImage(tag?.image, 'h_40,c_limit')}
578
+ style={styles.productTagImageStyle}
579
+ />
580
+ ) : (
581
+ <OIcon
582
+ src={theme.images?.dummies?.product}
583
+ style={styles.productTagImageStyle}
584
+ />
585
+ )}
586
+ <OText color={theme.colors.textSecondary} size={12} style={styles.productTagNameStyle}>{tag.name}</OText>
587
+ </View>
588
+ ))}
589
+ </ScrollView>
590
+ </ProductSummary>
563
591
  {loading && !product ? (
564
592
  <>
565
593
  {[...Array(2)].map((item, i) => (
@@ -658,7 +686,7 @@ export const ProductOptionsUI = (props: any) => {
658
686
  return (
659
687
  <React.Fragment key={`popt_${option.id}`}>
660
688
  {showOption(option) && (
661
- <View style={styles.optionContainer}>
689
+ <View style={styles.optionContainer} onLayout={(event: any) => handleOnLayout(event, option?.id)}>
662
690
  <ProductOption
663
691
  option={option}
664
692
  currentState={currentState}
@@ -695,6 +723,8 @@ export const ProductOptionsUI = (props: any) => {
695
723
  isSoldOut ||
696
724
  maxProductQuantity <= 0
697
725
  }
726
+ scrollDown={scrollDown}
727
+ error={errors[`id:${option.id}`]}
698
728
  />
699
729
  );
700
730
  },
@@ -855,7 +885,7 @@ export const ProductOptionsUI = (props: any) => {
855
885
  {qtyBy?.pieces && (
856
886
  <TextInput
857
887
  keyboardType='numeric'
858
- value={`${productCart?.quantity > 0 ? productCart?.quantity: ''}`}
888
+ value={`${productCart?.quantity > 0 ? productCart?.quantity : ''}`}
859
889
  onChangeText={(val: any) => onChangeProductCartQuantity(parseInt(val))}
860
890
  editable={!orderState.loading}
861
891
  style={{
@@ -71,7 +71,7 @@ export const ProductActions = styled.View`
71
71
  position: absolute;
72
72
  bottom: 0px;
73
73
  min-height: 70px;
74
- padding-top: ${(props : any) => props.ios ? '20px' : '0'};
74
+ padding-top: ${(props: any) => props.ios ? '20px' : '0'};
75
75
  padding-horizontal: 40px;
76
76
  width: 100%;
77
77
  flex-direction: row;
@@ -97,3 +97,5 @@ export const WeightUnitItem = styled.View`
97
97
  background-color: ${(props: any) => props.theme.colors.primary}20;
98
98
  `}
99
99
  `
100
+ export const ProductSummary = styled.View`
101
+ `
@@ -27,7 +27,9 @@ export const ProductOptionSubOptionUI = (props: any) => {
27
27
  suboption,
28
28
  toggleSelect,
29
29
  changePosition,
30
- disabled
30
+ disabled,
31
+ error,
32
+ scrollDown
31
33
  } = props
32
34
 
33
35
  const theme = useTheme();
@@ -38,6 +40,9 @@ export const ProductOptionSubOptionUI = (props: any) => {
38
40
 
39
41
  const handleSuboptionClick = () => {
40
42
  toggleSelect()
43
+ if (error) {
44
+ scrollDown(option?.id)
45
+ }
41
46
  if (balance === option?.max && option?.suboptions?.length > balance && !(option?.min === 1 && option?.max === 1)) {
42
47
  setShowMessage(true)
43
48
  }
@@ -193,6 +193,7 @@ export interface BusinessBasicInformationParams {
193
193
  isBusinessInfoShow?: boolean;
194
194
  header?: any;
195
195
  logo?: any;
196
+ isPreOrder?: boolean;
196
197
  }
197
198
  export interface BusinessProductsCategoriesParams {
198
199
  categories: Array<any>;