ordering-ui-react-native 0.16.49 → 0.16.50

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.49",
3
+ "version": "0.16.50",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -4,7 +4,9 @@ import {
4
4
  useUtils,
5
5
  useOrder,
6
6
  useLanguage,
7
- useConfig
7
+ useConfig,
8
+ useToast,
9
+ ToastType
8
10
  } from 'ordering-components/native';
9
11
  import { OIcon, OText } from '../shared';
10
12
  import { StyleSheet, TouchableOpacity, View } from 'react-native';
@@ -44,14 +46,16 @@ export const BusinessControllerUI = (props: BusinessControllerParams) => {
44
46
  businessDeliveryTime,
45
47
  businessPickupTime,
46
48
  businessDistance,
47
- handleFavoriteBusiness
49
+ handleFavoriteBusiness,
50
+ enableIntersection
48
51
  } = props;
49
52
  const [{ parsePrice, parseDistance, parseNumber, optimizeImage }] = useUtils();
53
+ const [, { showToast }] = useToast()
50
54
  const [orderState] = useOrder();
51
55
  const [configState] = useConfig();
52
56
  const [, t] = useLanguage();
53
57
  const theme = useTheme()
54
- const [isIntersectionObserver, setIsIntersectionObserver] = useState(false)
58
+ const [isIntersectionObserver, setIsIntersectionObserver] = useState(!enableIntersection)
55
59
  const styles = StyleSheet.create({
56
60
  headerStyle: {
57
61
  borderTopLeftRadius: 7.6,
@@ -121,7 +125,11 @@ export const BusinessControllerUI = (props: BusinessControllerParams) => {
121
125
  const handleBusinessClick = (selectedBusiness: any) => {
122
126
  if (business?.open) handleClick && handleClick(selectedBusiness)
123
127
  else {
124
- navigation.navigate('BusinessPreorder', { business: selectedBusiness, handleBusinessClick: handleClick })
128
+ if (configState?.configs?.preorder_status_enabled?.value === '1') {
129
+ navigation.navigate('BusinessPreorder', { business: selectedBusiness, handleBusinessClick: handleClick })
130
+ return
131
+ }
132
+ showToast(ToastType.Info, t('ERROR_ADD_PRODUCT_BUSINESS_CLOSED', 'The business is closed at the moment'));
125
133
  }
126
134
  }
127
135
 
@@ -239,6 +239,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
239
239
  {products.sort((a: any, b: any) => a.rank - b.rank).map((product: any, i: any) => (
240
240
  <SingleProductCard
241
241
  key={`${product?.id}_${i}`}
242
+ enableIntersection
242
243
  isSoldOut={product.inventoried && !product.quantity}
243
244
  businessId={businessId}
244
245
  product={product}
@@ -223,7 +223,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
223
223
  }, [currentCart])
224
224
 
225
225
  return (
226
- <IOScrollView rootMargin={{ top: 0, bottom: 0 }}>
226
+ <>
227
227
  <ContainerSafeAreaView
228
228
  style={{ flex: 1 }}
229
229
  isOpenFiltProducts={isOpenFiltProducts}
@@ -366,7 +366,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
366
366
  </>
367
367
  )}
368
368
  {!loading && business?.id && (
369
- <>
369
+ <IOScrollView rootMargin={{ top: 0, bottom: 0 }}>
370
370
  <WrapContent
371
371
  onLayout={(event: any) => setProductListLayout(event.nativeEvent.layout)}
372
372
  >
@@ -397,7 +397,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
397
397
  handleUpdateProducts={handleUpdateProducts}
398
398
  />
399
399
  </WrapContent>
400
- </>
400
+ </IOScrollView>
401
401
  )}
402
402
  {loading && !error && (
403
403
  <>
@@ -481,7 +481,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
481
481
  onClose={() => setOpenService(false)}
482
482
  />
483
483
  </OModal>
484
- </IOScrollView>
484
+ </>
485
485
  )
486
486
  }
487
487
 
@@ -1,5 +1,6 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
3
+ import { IOScrollView } from 'react-native-intersection-observer'
3
4
  import Geolocation from '@react-native-community/geolocation'
4
5
  import { getTrackingStatus, requestTrackingPermission } from 'react-native-tracking-transparency'
5
6
  import {
@@ -460,29 +461,32 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
460
461
  )}
461
462
  />
462
463
  )}
463
- {businessesList.businesses?.map(
464
- (business: any, i: number) => (
465
- <BusinessController
466
- key={`${business.id}_` + i}
467
- business={business}
468
- isBusinessOpen={business.open}
469
- handleCustomClick={handleBusinessClick}
470
- orderType={orderState?.options?.type}
471
- navigation={navigation}
472
- businessHeader={business?.header}
473
- businessFeatured={business?.featured}
474
- businessLogo={business?.logo}
475
- businessReviews={business?.reviews}
476
- businessDeliveryPrice={business?.delivery_price}
477
- businessDeliveryTime={business?.delivery_time}
478
- businessPickupTime={business?.pickup_time}
479
- businessDistance={business?.distance}
480
- handleUpdateBusinessList={handleUpdateBusinessList}
481
- favoriteIds={favoriteIds}
482
- setFavoriteIds={setFavoriteIds}
483
- />
484
- )
485
- )}
464
+ <IOScrollView>
465
+ {businessesList.businesses?.map(
466
+ (business: any, i: number) => (
467
+ <BusinessController
468
+ key={`${business.id}_` + i}
469
+ enableIntersection
470
+ business={business}
471
+ isBusinessOpen={business.open}
472
+ handleCustomClick={handleBusinessClick}
473
+ orderType={orderState?.options?.type}
474
+ navigation={navigation}
475
+ businessHeader={business?.header}
476
+ businessFeatured={business?.featured}
477
+ businessLogo={business?.logo}
478
+ businessReviews={business?.reviews}
479
+ businessDeliveryPrice={business?.delivery_price}
480
+ businessDeliveryTime={business?.delivery_time}
481
+ businessPickupTime={business?.pickup_time}
482
+ businessDistance={business?.distance}
483
+ handleUpdateBusinessList={handleUpdateBusinessList}
484
+ favoriteIds={favoriteIds}
485
+ setFavoriteIds={setFavoriteIds}
486
+ />
487
+ )
488
+ )}
489
+ </IOScrollView>
486
490
  {businessesList.loading && (
487
491
  <>
488
492
  {[
@@ -1,6 +1,7 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
3
3
  import Geolocation from '@react-native-community/geolocation'
4
+ import { IOScrollView } from 'react-native-intersection-observer'
4
5
  import { getTrackingStatus, requestTrackingPermission } from 'react-native-tracking-transparency'
5
6
  import {
6
7
  View,
@@ -162,7 +163,6 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
162
163
  const hasMore = !(
163
164
  paginationProps.totalPages === paginationProps.currentPage
164
165
  );
165
-
166
166
  if (y + PIXELS_TO_SCROLL > height && !businessesList.loading && hasMore) {
167
167
  getBusinesses();
168
168
  }
@@ -430,29 +430,32 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
430
430
  )}
431
431
  />
432
432
  )}
433
- {businessesList.businesses?.map(
434
- (business: any, i: number) => (
435
- <BusinessController
436
- key={`${business.id}_` + i}
437
- business={business}
438
- isBusinessOpen={business.open}
439
- handleCustomClick={handleBusinessClick}
440
- orderType={orderState?.options?.type}
441
- navigation={navigation}
442
- businessHeader={business?.header}
443
- businessFeatured={business?.featured}
444
- businessLogo={business?.logo}
445
- businessReviews={business?.reviews}
446
- businessDeliveryPrice={business?.delivery_price}
447
- businessDeliveryTime={business?.delivery_time}
448
- businessPickupTime={business?.pickup_time}
449
- businessDistance={business?.distance}
450
- handleUpdateBusinessList={handleUpdateBusinessList}
451
- favoriteIds={favoriteIds}
452
- setFavoriteIds={setFavoriteIds}
453
- />
454
- )
455
- )}
433
+ <IOScrollView>
434
+ {businessesList.businesses?.map(
435
+ (business: any, i: number) => (
436
+ <BusinessController
437
+ key={`${business.id}_` + i}
438
+ enableIntersection
439
+ business={business}
440
+ isBusinessOpen={business.open}
441
+ handleCustomClick={handleBusinessClick}
442
+ orderType={orderState?.options?.type}
443
+ navigation={navigation}
444
+ businessHeader={business?.header}
445
+ businessFeatured={business?.featured}
446
+ businessLogo={business?.logo}
447
+ businessReviews={business?.reviews}
448
+ businessDeliveryPrice={business?.delivery_price}
449
+ businessDeliveryTime={business?.delivery_time}
450
+ businessPickupTime={business?.pickup_time}
451
+ businessDistance={business?.distance}
452
+ handleUpdateBusinessList={handleUpdateBusinessList}
453
+ favoriteIds={favoriteIds}
454
+ setFavoriteIds={setFavoriteIds}
455
+ />
456
+ )
457
+ )}
458
+ </IOScrollView>
456
459
  {businessesList.loading && (
457
460
  <>
458
461
  {[
@@ -3,7 +3,6 @@ import React, { useState, useEffect } from 'react'
3
3
  import { useOrder, useSession } from 'ordering-components/native';
4
4
 
5
5
  import { useTheme } from 'styled-components/native'
6
- import { IOScrollView } from 'react-native-intersection-observer'
7
6
  import { BusinessesListing as OriginalBusinessListing } from './Layout/Original'
8
7
  import { BusinessesListing as AppointmentBusinessListing } from './Layout/Appointment'
9
8
 
@@ -43,9 +42,9 @@ export const BusinessesListing = (props: any) => {
43
42
  }, [auth])
44
43
 
45
44
  return (
46
- <IOScrollView rootMargin={{ top: 0, bottom: 0 }}>
45
+ <>
47
46
  {(layout === 'original') && <OriginalBusinessListing {...props} />}
48
47
  {(layout === 'appointment') && <AppointmentBusinessListing {...props} />}
49
- </IOScrollView>
48
+ </>
50
49
  )
51
50
  }
@@ -373,518 +373,518 @@ export const ProductOptionsUI = (props: any) => {
373
373
  <OIcon src={theme.images.general.arrow_left} width={30} />
374
374
  </TopActions>
375
375
  </TopHeader>
376
- <ScrollView ref={scrollViewRef}>
377
- {!error && (
378
- <View style={{ paddingBottom: 80 }}>
379
- <WrapHeader onLayout={(event: any) => setHeaderRefHeight(event.nativeEvent.layout?.height)}>
380
- {loading && !product ? (
381
- <View style={styles.productHeaderSkeleton}>
382
- <Placeholder Animation={Fade}>
383
- <PlaceholderLine
384
- height={258}
385
- style={{ borderRadius: 0 }}
386
- width={windowWidth}
387
- />
388
- </Placeholder>
389
- </View>
390
- ) : (
391
- <>
392
- <Swiper
393
- loop={false}
394
- ref={swiperRef}
395
- showsButtons={true}
396
- style={styles.mainSwiper}
397
- showsPagination={false}
398
- onIndexChanged={(index) => handleChangeMainIndex(index)}
399
- prevButton={
400
- <View style={styles.swiperButton}>
401
- <IconAntDesign
402
- name="caretleft"
403
- color={theme.colors.white}
404
- size={13}
405
- // style={styles.starIcon}
406
- />
407
- </View>
408
- }
409
- nextButton={
410
- <View style={styles.swiperButton}>
411
- <IconAntDesign
412
- name="caretright"
413
- color={theme.colors.white}
414
- size={13}
415
- // style={styles.starIcon}
376
+ {!error && (
377
+ <ScrollView
378
+ ref={scrollViewRef}
379
+ contentContainerStyle={{ paddingBottom: 80 }}
380
+ stickyHeaderIndices={[2]}>
381
+ <WrapHeader onLayout={(event: any) => setHeaderRefHeight(event.nativeEvent.layout?.height)}>
382
+ {loading && !product ? (
383
+ <View style={styles.productHeaderSkeleton}>
384
+ <Placeholder Animation={Fade}>
385
+ <PlaceholderLine
386
+ height={258}
387
+ style={{ borderRadius: 0 }}
388
+ width={windowWidth}
389
+ />
390
+ </Placeholder>
391
+ </View>
392
+ ) : (
393
+ <>
394
+ <Swiper
395
+ loop={false}
396
+ ref={swiperRef}
397
+ showsButtons={true}
398
+ style={styles.mainSwiper}
399
+ showsPagination={false}
400
+ onIndexChanged={(index) => handleChangeMainIndex(index)}
401
+ prevButton={
402
+ <View style={styles.swiperButton}>
403
+ <IconAntDesign
404
+ name="caretleft"
405
+ color={theme.colors.white}
406
+ size={13}
407
+ // style={styles.starIcon}
408
+ />
409
+ </View>
410
+ }
411
+ nextButton={
412
+ <View style={styles.swiperButton}>
413
+ <IconAntDesign
414
+ name="caretright"
415
+ color={theme.colors.white}
416
+ size={13}
417
+ // style={styles.starIcon}
418
+ />
419
+ </View>
420
+ }
421
+ >
422
+ {gallery && gallery.length > 0 && gallery.map((img, i) => (
423
+ <View
424
+ style={styles.slide1}
425
+ key={i}
426
+ >
427
+ {img.includes('image') ? (
428
+ <FastImage
429
+ style={{ height: '100%', opacity: isSoldOut ? 0.5 : 1 }}
430
+ source={{
431
+ uri: optimizeImage(img, 'h_1024,c_limit'),
432
+ priority: FastImage.priority.normal,
433
+ }}
416
434
  />
417
- </View>
418
- }
419
- >
420
- {gallery && gallery.length > 0 && gallery.map((img, i) => (
435
+ ) : (
436
+ <>
437
+ <YoutubePlayer
438
+ height={300}
439
+ play={playing}
440
+ videoId={img}
441
+ onChangeState={onStateChange}
442
+ />
443
+ <Button title={playing ? "pause" : "play"} onPress={togglePlaying} />
444
+ </>
445
+ )}
446
+ </View>
447
+ ))}
448
+ </Swiper>
449
+ <ScrollView
450
+ horizontal
451
+ contentContainerStyle={{
452
+ paddingHorizontal: 30,
453
+ paddingVertical: 15
454
+ }}
455
+ >
456
+ {gallery.length > 0 && gallery.map((img, index) => (
457
+ <TouchableOpacity
458
+ key={index}
459
+ onPress={() => handleClickThumb(index)}
460
+ >
421
461
  <View
422
- style={styles.slide1}
423
- key={i}
462
+ style={{
463
+ height: 56,
464
+ borderRadius: 8,
465
+ margin: 8,
466
+ opacity: index === thumbsSwiper ? 1 : 0.8
467
+ }}
424
468
  >
425
469
  {img.includes('image') ? (
426
- <FastImage
427
- style={{ height: '100%', opacity: isSoldOut ? 0.5 : 1 }}
428
- source={{
429
- uri: optimizeImage(img, 'h_1024,c_limit'),
430
- priority: FastImage.priority.normal,
470
+ <OIcon
471
+ url={img}
472
+ style={{
473
+ borderColor: theme.colors.lightGray,
474
+ borderRadius: 8,
475
+ minHeight: '100%',
476
+ opacity: isSoldOut ? 0.5 : 1
431
477
  }}
478
+ width={56}
479
+ height={56}
480
+ cover
432
481
  />
433
482
  ) : (
434
- <>
435
- <YoutubePlayer
436
- height={300}
437
- play={playing}
438
- videoId={img}
439
- onChangeState={onStateChange}
440
- />
441
- <Button title={playing ? "pause" : "play"} onPress={togglePlaying} />
442
- </>
483
+ <OIcon
484
+ url={'http://img.youtube.com/vi/' + img + '/0.jpg'}
485
+ style={{
486
+ borderColor: theme.colors.lightGray,
487
+ borderRadius: 8,
488
+ minHeight: '100%',
489
+ opacity: isSoldOut ? 0.5 : 1
490
+ }}
491
+ width={56}
492
+ height={56}
493
+ cover
494
+ />
443
495
  )}
444
496
  </View>
445
- ))}
446
- </Swiper>
447
- <ScrollView
448
- horizontal
449
- contentContainerStyle={{
450
- paddingHorizontal: 30,
451
- paddingVertical: 15
452
- }}
453
- >
454
- {gallery.length > 0 && gallery.map((img, index) => (
455
- <TouchableOpacity
456
- key={index}
457
- onPress={() => handleClickThumb(index)}
458
- >
459
- <View
460
- style={{
461
- height: 56,
462
- borderRadius: 8,
463
- margin: 8,
464
- opacity: index === thumbsSwiper ? 1 : 0.8
465
- }}
466
- >
467
- {img.includes('image') ? (
468
- <OIcon
469
- url={img}
470
- style={{
471
- borderColor: theme.colors.lightGray,
472
- borderRadius: 8,
473
- minHeight: '100%',
474
- opacity: isSoldOut ? 0.5 : 1
475
- }}
476
- width={56}
477
- height={56}
478
- cover
479
- />
480
- ) : (
481
- <OIcon
482
- url={'http://img.youtube.com/vi/' + img + '/0.jpg'}
483
- style={{
484
- borderColor: theme.colors.lightGray,
485
- borderRadius: 8,
486
- minHeight: '100%',
487
- opacity: isSoldOut ? 0.5 : 1
488
- }}
489
- width={56}
490
- height={56}
491
- cover
492
- />
493
- )}
494
- </View>
495
- </TouchableOpacity>
497
+ </TouchableOpacity>
496
498
 
497
- ))}
498
- </ScrollView>
499
+ ))}
500
+ </ScrollView>
501
+ </>
502
+ )}
503
+ </WrapHeader>
504
+ <ProductSummary onLayout={(event: any) => setSummaryRefHeight(event.nativeEvent.layout?.height)}>
505
+ <ProductTitle>
506
+ {loading && !product ? (
507
+ <Placeholder Animation={Fade}>
508
+ <View
509
+ style={{
510
+ flexDirection: 'row',
511
+ justifyContent: 'space-between',
512
+ }}>
513
+ <PlaceholderLine width={40} height={20} />
514
+ <PlaceholderLine width={30} height={20} />
515
+ </View>
516
+ </Placeholder>
517
+ ) : (
518
+ <>
519
+ <View style={{ flexDirection: 'row' }}>
520
+ <OText
521
+ size={20}
522
+ lineHeight={30}
523
+ weight={'600'}
524
+ style={{ flex: 1, marginBottom: 10 }}>
525
+ {product?.name || productCart.name}
526
+ </OText>
527
+ {!!product?.calories && (
528
+ <OText size={16} style={{ color: '#808080' }}>{product?.calories} cal
529
+ </OText>
530
+ )}
531
+ </View>
532
+ {((!!product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (!!product?.estimated_person)) && (
533
+ <OText size={14} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={'#909BA9'} mBottom={7}>
534
+ {
535
+ ((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (productCart?.sku && productCart?.sku !== '-1' && productCart?.sku !== '1'))
536
+ && <>{t('SKU', 'Sku')}{' '}{product?.sku || productCart?.sku}</>
537
+ }
538
+ {product?.sku && product?.sku !== '-1' && product?.sku !== '1' && product?.estimated_person && (
539
+ <>&nbsp;&#183;&nbsp;</>
540
+ )}
541
+ {product?.estimated_person
542
+ && <>{product?.estimated_person}{' '}{t('ESTIMATED_PERSONS', 'persons')}</>
543
+ }
544
+ </OText>
545
+ )}
546
+ {isHaveWeight ? (
547
+ <OText size={16} lineHeight={24} color={theme.colors.primary}>{parsePrice(pricePerWeightUnit)} / {product?.weight_unit}</OText>
548
+ ) : (
549
+ <View style={{ flexDirection: 'row', marginBottom: 10 }}>
550
+ <OText size={16} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={theme.colors.primary}>{productCart.price ? parsePrice(productCart.price) : ''}</OText>
551
+ {product?.offer_price !== null && product?.in_offer && (
552
+ <OText style={{
553
+ fontSize: 14,
554
+ color: '#808080',
555
+ textDecorationLine: 'line-through',
556
+ marginLeft: 7,
557
+ marginRight: 7
558
+ }}>{product?.offer_price ? parsePrice(product?.offer_price) : ''}</OText>
559
+ )}
560
+ </View>
561
+ )}
499
562
  </>
500
563
  )}
501
- </WrapHeader>
502
- <WrapContent>
503
- <ProductSummary onLayout={(event: any) => setSummaryRefHeight(event.nativeEvent.layout?.height)}>
504
- <ProductTitle>
505
- {loading && !product ? (
506
- <Placeholder Animation={Fade}>
507
- <View
508
- style={{
509
- flexDirection: 'row',
510
- justifyContent: 'space-between',
511
- }}>
512
- <PlaceholderLine width={40} height={20} />
513
- <PlaceholderLine width={30} height={20} />
514
- </View>
515
- </Placeholder>
564
+ </ProductTitle>
565
+ <ProductDescription>
566
+ <OText color={theme.colors.textSecondary} size={12} lineHeight={18}>
567
+ {product?.description || productCart?.description}
568
+ </OText>
569
+ </ProductDescription>
570
+ <ScrollView
571
+ horizontal
572
+ showsHorizontalScrollIndicator={false}
573
+ contentContainerStyle={{ paddingBottom: 30 }}
574
+ >
575
+ {product?.tags?.map((tag: any) => (
576
+ <View
577
+ key={tag.id}
578
+ style={styles.productTagWrapper}
579
+ >
580
+ {!!tag?.image ? (
581
+ <OIcon
582
+ url={optimizeImage(tag?.image, 'h_40,c_limit')}
583
+ style={styles.productTagImageStyle}
584
+ />
516
585
  ) : (
517
- <>
518
- <View style={{ flexDirection: 'row' }}>
519
- <OText
520
- size={20}
521
- lineHeight={30}
522
- weight={'600'}
523
- style={{ flex: 1, marginBottom: 10 }}>
524
- {product?.name || productCart.name}
525
- </OText>
526
- {!!product?.calories && (
527
- <OText size={16} style={{ color: '#808080' }}>{product?.calories} cal
528
- </OText>
529
- )}
530
- </View>
531
- {((!!product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (!!product?.estimated_person)) && (
532
- <OText size={14} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={'#909BA9'} mBottom={7}>
533
- {
534
- ((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (productCart?.sku && productCart?.sku !== '-1' && productCart?.sku !== '1'))
535
- && <>{t('SKU', 'Sku')}{' '}{product?.sku || productCart?.sku}</>
536
- }
537
- {product?.sku && product?.sku !== '-1' && product?.sku !== '1' && product?.estimated_person && (
538
- <>&nbsp;&#183;&nbsp;</>
539
- )}
540
- {product?.estimated_person
541
- && <>{product?.estimated_person}{' '}{t('ESTIMATED_PERSONS', 'persons')}</>
542
- }
543
- </OText>
544
- )}
545
- {isHaveWeight ? (
546
- <OText size={16} lineHeight={24} color={theme.colors.primary}>{parsePrice(pricePerWeightUnit)} / {product?.weight_unit}</OText>
547
- ) : (
548
- <View style={{ flexDirection: 'row', marginBottom: 10 }}>
549
- <OText size={16} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={theme.colors.primary}>{productCart.price ? parsePrice(productCart.price) : ''}</OText>
550
- {product?.offer_price !== null && product?.in_offer && (
551
- <OText style={{
552
- fontSize: 14,
553
- color: '#808080',
554
- textDecorationLine: 'line-through',
555
- marginLeft: 7,
556
- marginRight: 7
557
- }}>{product?.offer_price ? parsePrice(product?.offer_price) : ''}</OText>
558
- )}
559
- </View>
560
- )}
561
- </>
586
+ <OIcon
587
+ src={theme.images?.dummies?.product}
588
+ style={styles.productTagImageStyle}
589
+ />
562
590
  )}
563
- </ProductTitle>
564
- <ProductDescription>
565
- <OText color={theme.colors.textSecondary} size={12} lineHeight={18}>
566
- {product?.description || productCart?.description}
591
+ <OText color={theme.colors.textSecondary} size={12} style={styles.productTagNameStyle}>{tag.name}</OText>
592
+ </View>
593
+ ))}
594
+ </ScrollView>
595
+ </ProductSummary>
596
+ {(!loading && product) && (
597
+ <ExtraOptionWrap
598
+ horizontal
599
+ showsHorizontalScrollIndicator={false}
600
+ style={{ marginBottom: 20 }}
601
+ contentContainerStyle={{ marginHorizontal: 40, paddingHorizontal: 33, backgroundColor: theme.colors.white }}
602
+ >
603
+ <TouchableOpacity
604
+ key={`eopt_all_0`}
605
+ onPress={() => setSelectedOpt(0)}
606
+ style={[
607
+ styles.extraItem,
608
+ {
609
+ borderBottomColor: selOpt == 0 ? theme.colors.textNormal : theme.colors.border,
610
+ },
611
+ ]}>
612
+ <OText
613
+ color={selOpt == 0 ? theme.colors.textNormal : theme.colors.textSecondary}
614
+ size={selOpt == 0 ? 14 : 12}
615
+ weight={selOpt == 0 ? '600' : 'normal'}>
616
+ {t('ALL', 'All')}
617
+ </OText>
618
+ </TouchableOpacity>
619
+ {product?.ingredients.length > 0 && (
620
+ <TouchableOpacity
621
+ key={`eopt_all_00`}
622
+ onPress={() => setSelectedOpt(-1)}
623
+ style={[
624
+ styles.extraItem,
625
+ {
626
+ borderBottomColor:
627
+ selOpt == -1 ? theme.colors.textNormal : theme.colors.border,
628
+ },
629
+ ]}>
630
+ <OText
631
+ color={selOpt == -1 ? theme.colors.textNormal : theme.colors.textSecondary}
632
+ size={selOpt == -1 ? 14 : 12}
633
+ weight={selOpt == -1 ? '600' : 'normal'}>
634
+ {t('INGREDIENTS', 'Ingredients')}
567
635
  </OText>
568
- </ProductDescription>
569
- <ScrollView
570
- horizontal
571
- showsHorizontalScrollIndicator={false}
572
- contentContainerStyle={{ paddingBottom: 30 }}
573
- >
574
- {product?.tags?.map((tag: any) => (
636
+ </TouchableOpacity>
637
+ )}
638
+ {product?.extras.map((extra: any) =>
639
+ <ExtraOptions key={extra.id} options={extra.options} />
640
+ )}
641
+ </ExtraOptionWrap>
642
+ )}
643
+ {loading && !product ? (
644
+ <>
645
+ {[...Array(2)].map((item, i) => (
646
+ <Placeholder
647
+ key={i}
648
+ style={{ marginBottom: 20 }}
649
+ Animation={Fade}>
650
+ <PlaceholderLine
651
+ height={40}
652
+ style={{ flex: 1, marginTop: 10 }}
653
+ />
654
+ {[...Array(3)].map((item, i) => (
575
655
  <View
576
- key={tag.id}
577
- style={styles.productTagWrapper}
578
- >
579
- {!!tag?.image ? (
580
- <OIcon
581
- url={optimizeImage(tag?.image, 'h_40,c_limit')}
582
- style={styles.productTagImageStyle}
583
- />
584
- ) : (
585
- <OIcon
586
- src={theme.images?.dummies?.product}
587
- style={styles.productTagImageStyle}
588
- />
589
- )}
590
- <OText color={theme.colors.textSecondary} size={12} style={styles.productTagNameStyle}>{tag.name}</OText>
656
+ key={'place_key_' + i}
657
+ style={{
658
+ flexDirection: 'row',
659
+ justifyContent: 'space-between',
660
+ }}>
661
+ <PlaceholderLine
662
+ height={30}
663
+ width={10}
664
+ style={{ marginBottom: 20 }}
665
+ />
666
+ <PlaceholderLine
667
+ height={30}
668
+ width={50}
669
+ style={{ marginBottom: 20 }}
670
+ />
671
+ <PlaceholderLine
672
+ height={30}
673
+ width={30}
674
+ style={{ marginBottom: 20 }}
675
+ />
591
676
  </View>
592
677
  ))}
593
- </ScrollView>
594
- </ProductSummary>
595
- {loading && !product ? (
678
+ </Placeholder>
679
+ ))}
680
+ </>
681
+ ) : (
682
+ <ProductEditions>
683
+ {selOpt == 0 ? (
596
684
  <>
597
- {[...Array(2)].map((item, i) => (
598
- <Placeholder
599
- key={i}
600
- style={{ marginBottom: 20 }}
601
- Animation={Fade}>
602
- <PlaceholderLine
603
- height={40}
604
- style={{ flex: 1, marginTop: 10 }}
605
- />
606
- {[...Array(3)].map((item, i) => (
607
- <View
608
- key={'place_key_' + i}
609
- style={{
610
- flexDirection: 'row',
611
- justifyContent: 'space-between',
612
- }}>
613
- <PlaceholderLine
614
- height={30}
615
- width={10}
616
- style={{ marginBottom: 20 }}
617
- />
618
- <PlaceholderLine
619
- height={30}
620
- width={50}
621
- style={{ marginBottom: 20 }}
622
- />
623
- <PlaceholderLine
624
- height={30}
625
- width={30}
626
- style={{ marginBottom: 20 }}
685
+ {product?.ingredients.length > 0 && (
686
+ <View style={styles.optionContainer}>
687
+ <SectionTitle>
688
+ <OText size={16}>
689
+ {t('INGREDIENTS', 'Ingredients')}
690
+ </OText>
691
+ </SectionTitle>
692
+ <WrapperIngredients>
693
+ {product?.ingredients.map((ingredient: any) => (
694
+ <ProductIngredient
695
+ key={ingredient.id}
696
+ ingredient={ingredient}
697
+ state={
698
+ productCart.ingredients[`id:${ingredient.id}`]
699
+ }
700
+ onChange={handleChangeIngredientState}
701
+ isSoldOut={isSoldOut}
627
702
  />
628
- </View>
629
- ))}
630
- </Placeholder>
631
- ))}
703
+ ))}
704
+ </WrapperIngredients>
705
+ </View>
706
+ )}
707
+ {product?.extras.sort((a: any, b: any) => a.rank - b.rank).map((extra: any) =>
708
+ extra.options.sort((a: any, b: any) => a.rank - b.rank).map((option: any) => {
709
+ const currentState =
710
+ productCart.options[`id:${option.id}`] || {};
711
+ return (
712
+ <React.Fragment key={`popt_${option.id}`}>
713
+ {showOption(option) && (
714
+ <View style={styles.optionContainer} onLayout={(event: any) => handleOnLayout(event, option?.id)}>
715
+ <ProductOption
716
+ option={option}
717
+ currentState={currentState}
718
+ error={errors[`id:${option.id}`]}>
719
+ <WrapperSubOption
720
+ style={{
721
+ backgroundColor: isError(option.id),
722
+ borderRadius: 7.6
723
+ }}>
724
+ {option.suboptions.sort((a: any, b: any) => a.rank - b.rank).map(
725
+ (suboption: any) => {
726
+ const currentState =
727
+ productCart.options[
728
+ `id:${option.id}`
729
+ ]?.suboptions[
730
+ `id:${suboption.id}`
731
+ ] || {};
732
+ const balance =
733
+ productCart.options[
734
+ `id:${option.id}`
735
+ ]?.balance || 0;
736
+ return (
737
+ <ProductOptionSubOption
738
+ key={suboption.id}
739
+ isSoldOut={isSoldOut}
740
+ onChange={
741
+ handleChangeSuboptionState
742
+ }
743
+ balance={balance}
744
+ option={option}
745
+ suboption={suboption}
746
+ state={currentState}
747
+ disabled={
748
+ isSoldOut ||
749
+ maxProductQuantity <= 0
750
+ }
751
+ setIsScrollAvailable={setIsScrollAvailable}
752
+ error={errors[`id:${option.id}`]}
753
+ />
754
+ );
755
+ },
756
+ )}
757
+ </WrapperSubOption>
758
+ </ProductOption>
759
+ </View>
760
+ )}
761
+ </React.Fragment>
762
+ );
763
+ }),
764
+ )}
632
765
  </>
633
766
  ) : (
634
- <ProductEditions>
635
- <ExtraOptionWrap
636
- horizontal
637
- showsHorizontalScrollIndicator={false}
638
- style={{ marginBottom: 20 }}
639
- contentContainerStyle={{ paddingHorizontal: 33 }}
640
- >
641
- <TouchableOpacity
642
- key={`eopt_all_0`}
643
- onPress={() => setSelectedOpt(0)}
644
- style={[
645
- styles.extraItem,
646
- {
647
- borderBottomColor: selOpt == 0 ? theme.colors.textNormal : theme.colors.border,
648
- },
649
- ]}>
650
- <OText
651
- color={selOpt == 0 ? theme.colors.textNormal : theme.colors.textSecondary}
652
- size={selOpt == 0 ? 14 : 12}
653
- weight={selOpt == 0 ? '600' : 'normal'}>
654
- {t('ALL', 'All')}
655
- </OText>
656
- </TouchableOpacity>
657
- {product?.ingredients.length > 0 && (
658
- <TouchableOpacity
659
- key={`eopt_all_00`}
660
- onPress={() => setSelectedOpt(-1)}
661
- style={[
662
- styles.extraItem,
663
- {
664
- borderBottomColor:
665
- selOpt == -1 ? theme.colors.textNormal : theme.colors.border,
666
- },
667
- ]}>
668
- <OText
669
- color={selOpt == -1 ? theme.colors.textNormal : theme.colors.textSecondary}
670
- size={selOpt == -1 ? 14 : 12}
671
- weight={selOpt == -1 ? '600' : 'normal'}>
767
+ <>
768
+ {selOpt == -1 ? (
769
+ <View style={styles.optionContainer}>
770
+ <SectionTitle>
771
+ <OText size={16}>
672
772
  {t('INGREDIENTS', 'Ingredients')}
673
773
  </OText>
674
- </TouchableOpacity>
675
- )}
676
- {product?.extras.map((extra: any) =>
677
- <ExtraOptions key={extra.id} options={extra.options} />
678
- )}
679
- </ExtraOptionWrap>
680
-
681
- {selOpt == 0 ? (
774
+ </SectionTitle>
775
+ <WrapperIngredients>
776
+ {product?.ingredients.map((ingredient: any) => (
777
+ <ProductIngredient
778
+ key={ingredient.id}
779
+ ingredient={ingredient}
780
+ state={
781
+ productCart.ingredients[`id:${ingredient.id}`]
782
+ }
783
+ onChange={handleChangeIngredientState}
784
+ isSoldOut={isSoldOut}
785
+ />
786
+ ))}
787
+ </WrapperIngredients>
788
+ </View>
789
+ ) : (
682
790
  <>
683
- {product?.ingredients.length > 0 && (
684
- <View style={styles.optionContainer}>
685
- <SectionTitle>
686
- <OText size={16}>
687
- {t('INGREDIENTS', 'Ingredients')}
688
- </OText>
689
- </SectionTitle>
690
- <WrapperIngredients>
691
- {product?.ingredients.map((ingredient: any) => (
692
- <ProductIngredient
693
- key={ingredient.id}
694
- ingredient={ingredient}
695
- state={
696
- productCart.ingredients[`id:${ingredient.id}`]
697
- }
698
- onChange={handleChangeIngredientState}
699
- isSoldOut={isSoldOut}
700
- />
701
- ))}
702
- </WrapperIngredients>
703
- </View>
704
- )}
705
- {product?.extras.sort((a: any, b: any) => a.rank - b.rank).map((extra: any) =>
791
+ {product?.extras.map((extra: any) =>
706
792
  extra.options.sort((a: any, b: any) => a.rank - b.rank).map((option: any) => {
707
- const currentState =
708
- productCart.options[`id:${option.id}`] || {};
709
- return (
710
- <React.Fragment key={`popt_${option.id}`}>
711
- {showOption(option) && (
712
- <View style={styles.optionContainer} onLayout={(event: any) => handleOnLayout(event, option?.id)}>
713
- <ProductOption
714
- option={option}
715
- currentState={currentState}
716
- error={errors[`id:${option.id}`]}>
717
- <WrapperSubOption
718
- style={{
719
- backgroundColor: isError(option.id),
720
- borderRadius: 7.6
721
- }}>
722
- {option.suboptions.sort((a: any, b: any) => a.rank - b.rank).map(
723
- (suboption: any) => {
724
- const currentState =
725
- productCart.options[
726
- `id:${option.id}`
727
- ]?.suboptions[
728
- `id:${suboption.id}`
729
- ] || {};
730
- const balance =
731
- productCart.options[
732
- `id:${option.id}`
733
- ]?.balance || 0;
734
- return (
735
- <ProductOptionSubOption
736
- key={suboption.id}
737
- isSoldOut={isSoldOut}
738
- onChange={
739
- handleChangeSuboptionState
740
- }
741
- balance={balance}
742
- option={option}
743
- suboption={suboption}
744
- state={currentState}
745
- disabled={
746
- isSoldOut ||
747
- maxProductQuantity <= 0
748
- }
749
- setIsScrollAvailable={setIsScrollAvailable}
750
- error={errors[`id:${option.id}`]}
751
- />
752
- );
753
- },
754
- )}
755
- </WrapperSubOption>
756
- </ProductOption>
757
- </View>
758
- )}
759
- </React.Fragment>
760
- );
793
+ if (
794
+ option.id == selOpt ||
795
+ (hasRespected(
796
+ extra.options,
797
+ option.respect_to,
798
+ ) &&
799
+ showOption(option))
800
+ ) {
801
+ const currentState =
802
+ productCart.options[`id:${option.id}`] || {};
803
+ return (
804
+ <React.Fragment key={option.id}>
805
+ {showOption(option) && (
806
+ <View style={styles.optionContainer}>
807
+ <ProductOption
808
+ option={option}
809
+ currentState={currentState}
810
+ error={errors[`id:${option.id}`]}>
811
+ <WrapperSubOption
812
+ style={{
813
+ backgroundColor: isError(
814
+ option.id,
815
+ ),
816
+ }}>
817
+ {option.suboptions.sort((a: any, b: any) => a.rank - b.rank).map(
818
+ (suboption: any) => {
819
+ const currentState =
820
+ productCart.options[
821
+ `id:${option.id}`
822
+ ]?.suboptions[
823
+ `id:${suboption.id}`
824
+ ] || {};
825
+ const balance =
826
+ productCart.options[
827
+ `id:${option.id}`
828
+ ]?.balance || 0;
829
+ return (
830
+ <ProductOptionSubOption
831
+ key={suboption.id}
832
+ onChange={
833
+ handleChangeSuboptionState
834
+ }
835
+ balance={balance}
836
+ option={option}
837
+ suboption={suboption}
838
+ state={currentState}
839
+ disabled={
840
+ isSoldOut ||
841
+ maxProductQuantity <= 0
842
+ }
843
+ />
844
+ );
845
+ },
846
+ )}
847
+ </WrapperSubOption>
848
+ </ProductOption>
849
+ </View>
850
+ )}
851
+ </React.Fragment>
852
+ );
853
+ }
761
854
  }),
762
855
  )}
763
856
  </>
764
- ) : (
765
- <>
766
- {selOpt == -1 ? (
767
- <View style={styles.optionContainer}>
768
- <SectionTitle>
769
- <OText size={16}>
770
- {t('INGREDIENTS', 'Ingredients')}
771
- </OText>
772
- </SectionTitle>
773
- <WrapperIngredients>
774
- {product?.ingredients.map((ingredient: any) => (
775
- <ProductIngredient
776
- key={ingredient.id}
777
- ingredient={ingredient}
778
- state={
779
- productCart.ingredients[`id:${ingredient.id}`]
780
- }
781
- onChange={handleChangeIngredientState}
782
- isSoldOut={isSoldOut}
783
- />
784
- ))}
785
- </WrapperIngredients>
786
- </View>
787
- ) : (
788
- <>
789
- {product?.extras.map((extra: any) =>
790
- extra.options.sort((a: any, b: any) => a.rank - b.rank).map((option: any) => {
791
- if (
792
- option.id == selOpt ||
793
- (hasRespected(
794
- extra.options,
795
- option.respect_to,
796
- ) &&
797
- showOption(option))
798
- ) {
799
- const currentState =
800
- productCart.options[`id:${option.id}`] || {};
801
- return (
802
- <React.Fragment key={option.id}>
803
- {showOption(option) && (
804
- <View style={styles.optionContainer}>
805
- <ProductOption
806
- option={option}
807
- currentState={currentState}
808
- error={errors[`id:${option.id}`]}>
809
- <WrapperSubOption
810
- style={{
811
- backgroundColor: isError(
812
- option.id,
813
- ),
814
- }}>
815
- {option.suboptions.sort((a: any, b: any) => a.rank - b.rank).map(
816
- (suboption: any) => {
817
- const currentState =
818
- productCart.options[
819
- `id:${option.id}`
820
- ]?.suboptions[
821
- `id:${suboption.id}`
822
- ] || {};
823
- const balance =
824
- productCart.options[
825
- `id:${option.id}`
826
- ]?.balance || 0;
827
- return (
828
- <ProductOptionSubOption
829
- key={suboption.id}
830
- onChange={
831
- handleChangeSuboptionState
832
- }
833
- balance={balance}
834
- option={option}
835
- suboption={suboption}
836
- state={currentState}
837
- disabled={
838
- isSoldOut ||
839
- maxProductQuantity <= 0
840
- }
841
- />
842
- );
843
- },
844
- )}
845
- </WrapperSubOption>
846
- </ProductOption>
847
- </View>
848
- )}
849
- </React.Fragment>
850
- );
851
- }
852
- }),
853
- )}
854
- </>
855
- )}
856
- </>
857
- )}
858
- {!product?.hide_special_instructions && (
859
- <ProductComment>
860
- <SectionTitle>
861
- <OText size={16} weight={'600'} lineHeight={24}>
862
- {t('SPECIAL_COMMENT', 'Special comment')}
863
- </OText>
864
- </SectionTitle>
865
- <OInput
866
- multiline
867
- placeholder={t('SPECIAL_COMMENT', 'Special comment')}
868
- value={productCart.comment}
869
- onChange={(val: string) =>
870
- handleChangeCommentState({ target: { value: val } })
871
- }
872
- isDisabled={
873
- !(productCart && !isSoldOut && maxProductQuantity)
874
- }
875
- style={styles.comment}
876
- />
877
- </ProductComment>
878
857
  )}
879
- </ProductEditions>
858
+ </>
880
859
  )}
881
- </WrapContent>
882
- </View>
883
- )}
884
- {!!error && error.length > 0 && (
885
- <NotFoundSource content={error[0]?.message || error[0]} />
886
- )}
887
- </ScrollView>
860
+ {!product?.hide_special_instructions && (
861
+ <ProductComment>
862
+ <SectionTitle>
863
+ <OText size={16} weight={'600'} lineHeight={24}>
864
+ {t('SPECIAL_COMMENT', 'Special comment')}
865
+ </OText>
866
+ </SectionTitle>
867
+ <OInput
868
+ multiline
869
+ placeholder={t('SPECIAL_COMMENT', 'Special comment')}
870
+ value={productCart.comment}
871
+ onChange={(val: string) =>
872
+ handleChangeCommentState({ target: { value: val } })
873
+ }
874
+ isDisabled={
875
+ !(productCart && !isSoldOut && maxProductQuantity)
876
+ }
877
+ style={styles.comment}
878
+ />
879
+ </ProductComment>
880
+ )}
881
+ </ProductEditions>
882
+ )}
883
+ {!!error && error.length > 0 && (
884
+ <NotFoundSource content={error[0]?.message || error[0]} />
885
+ )}
886
+ </ScrollView>
887
+ )}
888
888
  {!loading && !error && product && (
889
889
  <ProductActions ios={Platform?.OS === 'ios'}>
890
890
  <View>
@@ -49,7 +49,7 @@ export const ProductDescription = styled.View`
49
49
  `
50
50
 
51
51
  export const ProductEditions = styled.View`
52
-
52
+ padding: 0 40px;
53
53
  `
54
54
 
55
55
  export const SectionTitle = styled.View`
@@ -99,4 +99,8 @@ export const WeightUnitItem = styled.View`
99
99
  `}
100
100
  `
101
101
  export const ProductSummary = styled.View`
102
+ padding: 26px 40px;
103
+ position: relative;
104
+ background-color: white;
105
+ z-index: 100;
102
106
  `
@@ -31,7 +31,8 @@ const SinguleProductCardUI = React.memo((props: SingleProductCardParams) => {
31
31
  onProductClick,
32
32
  productAddedToCartLength,
33
33
  style,
34
- handleFavoriteProduct
34
+ handleFavoriteProduct,
35
+ enableIntersection
35
36
  } = props;
36
37
 
37
38
  const theme = useTheme();
@@ -89,7 +90,7 @@ const SinguleProductCardUI = React.memo((props: SingleProductCardParams) => {
89
90
  const [stateConfig] = useConfig();
90
91
  const [{ parsePrice, optimizeImage }] = useUtils();
91
92
  const [orderState] = useOrder();
92
- const [isIntersectionObserver, setIsIntersectionObserver] = useState(false)
93
+ const [isIntersectionObserver, setIsIntersectionObserver] = useState(!enableIntersection)
93
94
  const editMode = typeof product?.code !== 'undefined';
94
95
 
95
96
  const removeToBalance = editMode ? product?.quantity : 0;
@@ -213,6 +213,7 @@ export interface BusinessControllerParams {
213
213
  handleFavoriteBusiness?: any,
214
214
  setFavoriteIds?: any;
215
215
  handleUpdateBusinessList?: any;
216
+ enableIntersection?: boolean;
216
217
  }
217
218
  export interface BusinessProductsListingParams {
218
219
  navigation?: any;
@@ -289,15 +290,16 @@ export interface BusinessProductsListParams {
289
290
  handleUpdateProducts?: any
290
291
  }
291
292
  export interface SingleProductCardParams {
292
- businessId: any,
293
+ businessId: any;
293
294
  product: any;
294
295
  isSoldOut: boolean;
295
296
  onProductClick: any;
296
297
  productAddedToCartLength: number;
297
- style?: ViewStyle,
298
- categoryState?: any,
299
- handleFavoriteProduct?: any,
300
- handleUpdateProducts?: any
298
+ style?: ViewStyle;
299
+ categoryState?: any;
300
+ handleFavoriteProduct?: any;
301
+ handleUpdateProducts?: any;
302
+ enableIntersection?: boolean;
301
303
  }
302
304
  export interface BusinessInformationParams {
303
305
  navigation?: any,