ordering-ui-react-native 0.16.22 → 0.16.23-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.
Files changed (197) hide show
  1. package/package.json +7 -4
  2. package/src/DeliveryApp.tsx +43 -1
  3. package/src/components/ActiveOrders/index.tsx +61 -63
  4. package/src/components/ActiveOrders/styles.tsx +8 -14
  5. package/src/components/AddressForm/index.tsx +18 -2
  6. package/src/components/BusinessBasicInformation/index.tsx +11 -19
  7. package/src/components/BusinessController/index.tsx +10 -8
  8. package/src/components/BusinessInformation/index.tsx +33 -4
  9. package/src/components/BusinessInformation/styles.tsx +2 -2
  10. package/src/components/BusinessProductsList/index.tsx +10 -10
  11. package/src/components/BusinessesListing/index.tsx +1 -1
  12. package/src/components/Checkout/index.tsx +2 -1
  13. package/src/components/LanguageSelector/index.tsx +21 -16
  14. package/src/components/LoginForm/index.tsx +118 -30
  15. package/src/components/LoginForm/styles.tsx +6 -0
  16. package/src/components/Messages/index.tsx +2 -2
  17. package/src/components/NotificationSetting/index.tsx +85 -0
  18. package/src/components/OrderDetails/index.tsx +2 -20
  19. package/src/components/OrdersOption/index.tsx +54 -56
  20. package/src/components/PaymentOptions/index.tsx +335 -365
  21. package/src/components/PaymentOptionsWebView/index.tsx +120 -121
  22. package/src/components/ReviewDriver/index.tsx +1 -1
  23. package/src/components/ReviewOrder/index.tsx +2 -1
  24. package/src/components/ReviewProducts/index.tsx +11 -0
  25. package/src/components/SignupForm/index.tsx +143 -61
  26. package/src/components/SingleProductReview/index.tsx +8 -5
  27. package/src/components/StripeElementsForm/index.tsx +25 -16
  28. package/src/components/VerifyPhone/styles.tsx +1 -2
  29. package/src/components/shared/OBottomPopup.tsx +6 -2
  30. package/src/index.tsx +2 -0
  31. package/src/pages/BusinessesListing.tsx +7 -6
  32. package/src/pages/OrderDetails.tsx +1 -1
  33. package/src/pages/ReviewDriver.tsx +2 -2
  34. package/src/pages/ReviewOrder.tsx +2 -2
  35. package/src/theme.json +0 -1
  36. package/src/types/@fatnlazycat/react-native-recaptcha-v3/index.d.ts +1 -0
  37. package/src/types/index.tsx +13 -9
  38. package/src/utils/index.tsx +0 -1
  39. package/themes/business/index.tsx +4 -0
  40. package/themes/business/src/components/BusinessController/index.tsx +2 -2
  41. package/themes/business/src/components/Chat/index.tsx +42 -34
  42. package/themes/business/src/components/DriverMap/index.tsx +7 -5
  43. package/themes/business/src/components/DriverSchedule/index.tsx +71 -0
  44. package/themes/business/src/components/DriverSchedule/styles.tsx +6 -0
  45. package/themes/business/src/components/LoginForm/index.tsx +111 -74
  46. package/themes/business/src/components/MapView/index.tsx +12 -1
  47. package/themes/business/src/components/MessagesOption/index.tsx +11 -1
  48. package/themes/business/src/components/OrderDetails/Business.tsx +1 -1
  49. package/themes/business/src/components/OrderDetails/OrderContentComponent.tsx +25 -19
  50. package/themes/business/src/components/OrdersListManager/index.tsx +10 -3
  51. package/themes/business/src/components/OrdersOption/index.tsx +65 -21
  52. package/themes/business/src/components/OrdersOption/styles.tsx +5 -1
  53. package/themes/business/src/components/OrdersOptionBusiness/index.tsx +15 -1
  54. package/themes/business/src/components/OrdersOptionCity/index.tsx +15 -1
  55. package/themes/business/src/components/OrdersOptionDate/index.tsx +19 -6
  56. package/themes/business/src/components/OrdersOptionDelivery/index.tsx +15 -1
  57. package/themes/business/src/components/OrdersOptionDriver/index.tsx +15 -1
  58. package/themes/business/src/components/OrdersOptionPaymethod/index.tsx +15 -1
  59. package/themes/business/src/components/OrdersOptionStatus/index.tsx +10 -1
  60. package/themes/business/src/components/PreviousMessages/index.tsx +17 -18
  61. package/themes/business/src/components/PreviousOrders/index.tsx +21 -23
  62. package/themes/business/src/components/ProductItemAccordion/index.tsx +5 -4
  63. package/themes/business/src/components/ReviewCustomer/index.tsx +1 -1
  64. package/themes/business/src/components/ScheduleBlocked/index.tsx +53 -0
  65. package/themes/business/src/components/UserFormDetails/index.tsx +5 -2
  66. package/themes/business/src/components/UserProfileForm/index.tsx +28 -4
  67. package/themes/business/src/components/shared/ODropDown.tsx +42 -8
  68. package/themes/business/src/components/shared/ODropDownCalendar.tsx +36 -7
  69. package/themes/business/src/components/shared/OModal.tsx +40 -37
  70. package/themes/business/src/types/index.tsx +15 -9
  71. package/themes/business/src/utils/index.tsx +10 -0
  72. package/themes/doordash/src/components/BusinessesListing/index.tsx +1 -1
  73. package/themes/doordash/src/components/LoginForm/index.tsx +1 -2
  74. package/themes/instacart/src/components/BusinessesListing/index.tsx +1 -1
  75. package/themes/kiosk/src/components/Checkout/index.tsx +6 -0
  76. package/themes/kiosk/src/components/LoginForm/index.tsx +121 -10
  77. package/themes/kiosk/src/components/LoginForm/styles.tsx +5 -0
  78. package/themes/kiosk/src/components/NavBar/index.tsx +14 -14
  79. package/themes/kiosk/src/components/OptionCard/index.tsx +1 -1
  80. package/themes/kiosk/src/components/OrderTypeCardSelector/index.tsx +8 -10
  81. package/themes/kiosk/src/components/shared/OButton.tsx +5 -18
  82. package/themes/kiosk/src/types/index.d.ts +2 -0
  83. package/themes/original/index.tsx +12 -0
  84. package/themes/original/src/components/AddressForm/index.tsx +136 -133
  85. package/themes/original/src/components/AddressList/index.tsx +1 -1
  86. package/themes/original/src/components/AppleLogin/index.tsx +4 -4
  87. package/themes/original/src/components/BusinessBasicInformation/index.tsx +304 -160
  88. package/themes/original/src/components/BusinessBasicInformation/styles.tsx +6 -2
  89. package/themes/original/src/components/BusinessController/index.tsx +175 -110
  90. package/themes/original/src/components/BusinessItemAccordion/index.tsx +8 -6
  91. package/themes/original/src/components/BusinessListingSearch/BusinessControllerSkeletons/index.tsx +57 -0
  92. package/themes/original/src/components/BusinessListingSearch/MaxSectionItem/index.tsx +59 -0
  93. package/themes/original/src/components/BusinessListingSearch/MaxSectionItem/styles.tsx +13 -0
  94. package/themes/original/src/components/BusinessListingSearch/index.tsx +101 -125
  95. package/themes/original/src/components/BusinessListingSearch/styles.tsx +18 -13
  96. package/themes/original/src/components/BusinessProductsList/SubcategoriesComponent/index.tsx +87 -0
  97. package/themes/original/src/components/BusinessProductsList/SubcategoriesComponent/styles.tsx +12 -0
  98. package/themes/original/src/components/BusinessProductsList/index.tsx +49 -52
  99. package/themes/original/src/components/BusinessProductsList/styles.tsx +0 -3
  100. package/themes/original/src/components/BusinessProductsListing/index.tsx +287 -175
  101. package/themes/original/src/components/BusinessProductsListing/styles.tsx +22 -8
  102. package/themes/original/src/components/BusinessReviews/index.tsx +6 -1
  103. package/themes/original/src/components/BusinessTypeFilter/index.tsx +109 -40
  104. package/themes/original/src/components/BusinessTypeFilter/styles.tsx +2 -0
  105. package/themes/original/src/components/BusinessesListing/Layout/Appointment/index.tsx +561 -0
  106. package/themes/original/src/components/BusinessesListing/{styles.tsx → Layout/Appointment/styles.tsx} +24 -10
  107. package/themes/original/src/components/BusinessesListing/Layout/Original/index.tsx +676 -0
  108. package/themes/original/src/components/BusinessesListing/Layout/Original/styles.tsx +137 -0
  109. package/themes/original/src/components/BusinessesListing/index.tsx +105 -519
  110. package/themes/original/src/components/Cart/index.tsx +42 -10
  111. package/themes/original/src/components/Cart/styles.tsx +4 -0
  112. package/themes/original/src/components/CartContent/index.tsx +22 -16
  113. package/themes/original/src/components/Checkout/index.tsx +106 -66
  114. package/themes/original/src/components/Checkout/styles.tsx +0 -1
  115. package/themes/original/src/components/DriverTips/index.tsx +4 -4
  116. package/themes/original/src/components/DriverTips/styles.tsx +2 -1
  117. package/themes/original/src/components/Favorite/index.tsx +1 -0
  118. package/themes/original/src/components/FavoriteList/index.tsx +32 -2
  119. package/themes/original/src/components/FloatingButton/styles.tsx +1 -1
  120. package/themes/original/src/components/GPSButton/index.tsx +20 -19
  121. package/themes/original/src/components/GoogleMap/index.tsx +20 -12
  122. package/themes/original/src/components/HelpAccountAndPayment/index.tsx +8 -3
  123. package/themes/original/src/components/HelpGuide/index.tsx +8 -3
  124. package/themes/original/src/components/HelpOrder/index.tsx +8 -3
  125. package/themes/original/src/components/LanguageSelector/index.tsx +19 -14
  126. package/themes/original/src/components/LoginForm/Otp/index.tsx +3 -2
  127. package/themes/original/src/components/LoginForm/index.tsx +82 -44
  128. package/themes/original/src/components/Messages/index.tsx +17 -17
  129. package/themes/original/src/components/MomentSelector/index.tsx +197 -0
  130. package/themes/original/src/components/MomentSelector/styles.tsx +6 -0
  131. package/themes/original/src/components/MultiCheckout/index.tsx +6 -0
  132. package/themes/original/src/components/MultiOrdersDetails/index.tsx +20 -16
  133. package/themes/original/src/components/MyOrders/index.tsx +68 -6
  134. package/themes/original/src/components/NavBar/index.tsx +15 -9
  135. package/themes/original/src/components/NetworkError/index.tsx +5 -3
  136. package/themes/original/src/components/NotFoundSource/index.tsx +2 -1
  137. package/themes/original/src/components/Notifications/index.tsx +148 -0
  138. package/themes/original/src/components/Notifications/styles.tsx +17 -0
  139. package/themes/original/src/components/OrderDetails/OrderHistory.tsx +167 -0
  140. package/themes/original/src/components/OrderDetails/index.tsx +190 -35
  141. package/themes/original/src/components/OrderDetails/styles.tsx +15 -2
  142. package/themes/original/src/components/OrderItAgain/index.tsx +75 -0
  143. package/themes/original/src/components/OrderItAgain/styles.tsx +10 -0
  144. package/themes/original/src/components/OrderProgress/index.tsx +8 -2
  145. package/themes/original/src/components/OrderSummary/index.tsx +1 -34
  146. package/themes/original/src/components/OrderTypeSelector/index.tsx +85 -36
  147. package/themes/original/src/components/OrderTypeSelector/styles.tsx +19 -1
  148. package/themes/original/src/components/OrdersOption/PreviousBusinessOrdered/index.tsx +100 -106
  149. package/themes/original/src/components/OrdersOption/PreviousProductsOrdered/index.tsx +17 -12
  150. package/themes/original/src/components/OrdersOption/index.tsx +71 -55
  151. package/themes/original/src/components/PaymentOptionWallet/index.tsx +56 -56
  152. package/themes/original/src/components/PaymentOptions/index.tsx +57 -37
  153. package/themes/original/src/components/PhoneInputNumber/index.tsx +4 -10
  154. package/themes/original/src/components/PlaceSpot/index.tsx +243 -47
  155. package/themes/original/src/components/PlaceSpot/styles.tsx +0 -2
  156. package/themes/original/src/components/PreviousOrders/index.tsx +3 -2
  157. package/themes/original/src/components/ProductForm/index.tsx +712 -655
  158. package/themes/original/src/components/ProductForm/styles.tsx +9 -7
  159. package/themes/original/src/components/ProductItemAccordion/index.tsx +198 -127
  160. package/themes/original/src/components/ProductOption/index.tsx +1 -1
  161. package/themes/original/src/components/ProfessionalFilter/index.tsx +129 -0
  162. package/themes/original/src/components/ProfessionalFilter/styles.tsx +0 -0
  163. package/themes/original/src/components/ProfessionalProfile/index.tsx +309 -0
  164. package/themes/original/src/components/ProfessionalProfile/styles.tsx +46 -0
  165. package/themes/original/src/components/ReviewDriver/index.tsx +6 -6
  166. package/themes/original/src/components/ReviewOrder/index.tsx +18 -3
  167. package/themes/original/src/components/ReviewProducts/index.tsx +1 -1
  168. package/themes/original/src/components/ReviewTrigger/index.tsx +118 -0
  169. package/themes/original/src/components/ReviewTrigger/styles.tsx +34 -0
  170. package/themes/original/src/components/SearchBar/index.tsx +5 -3
  171. package/themes/original/src/components/ServiceForm/index.tsx +631 -0
  172. package/themes/original/src/components/ServiceForm/styles.tsx +50 -0
  173. package/themes/original/src/components/SignupForm/index.tsx +350 -206
  174. package/themes/original/src/components/SingleOrderCard/index.tsx +214 -179
  175. package/themes/original/src/components/SingleProductCard/index.tsx +198 -104
  176. package/themes/original/src/components/SingleProductCard/styles.tsx +2 -2
  177. package/themes/original/src/components/SingleProductReview/index.tsx +38 -5
  178. package/themes/original/src/components/SingleProductReview/styles.tsx +12 -0
  179. package/themes/original/src/components/StripeElementsForm/index.tsx +15 -7
  180. package/themes/original/src/components/UpsellingProducts/index.tsx +14 -4
  181. package/themes/original/src/components/UserDetails/index.tsx +31 -17
  182. package/themes/original/src/components/UserFormDetails/index.tsx +74 -81
  183. package/themes/original/src/components/UserProfile/index.tsx +57 -29
  184. package/themes/original/src/components/UserProfile/styles.ts +17 -0
  185. package/themes/original/src/components/UserProfileForm/index.tsx +15 -10
  186. package/themes/original/src/components/WalletTransactions/index.tsx +76 -0
  187. package/themes/original/src/components/WalletTransactions/styles.tsx +13 -0
  188. package/themes/original/src/components/Wallets/index.tsx +174 -162
  189. package/themes/original/src/components/Wallets/styles.tsx +10 -8
  190. package/themes/original/src/components/shared/OBottomPopup.tsx +47 -14
  191. package/themes/original/src/components/shared/OButton.tsx +10 -3
  192. package/themes/original/src/components/shared/OIcon.tsx +8 -1
  193. package/themes/original/src/components/shared/OInput.tsx +3 -2
  194. package/themes/original/src/layouts/FloatingBottomContainer.tsx +5 -1
  195. package/themes/original/src/types/index.tsx +122 -30
  196. package/themes/original/src/utils/index.tsx +77 -0
  197. package/themes/uber-eats/src/components/BusinessesListing/index.tsx +1 -1
@@ -1,4 +1,16 @@
1
- import React, { useEffect, useRef, useCallback } from 'react';
1
+ import React, { useEffect, useRef, useState, useCallback } from 'react';
2
+ import {
3
+ View,
4
+ Keyboard,
5
+ TextInput,
6
+ TouchableOpacity,
7
+ StyleSheet,
8
+ Dimensions,
9
+ I18nManager,
10
+ SafeAreaView,
11
+ Platform,
12
+ Button
13
+ } from 'react-native';
2
14
  import {
3
15
  ProductForm as ProductOptions,
4
16
  useSession,
@@ -15,17 +27,10 @@ import Swiper from 'react-native-swiper'
15
27
  import FastImage from 'react-native-fast-image';
16
28
  import IconAntDesign from 'react-native-vector-icons/AntDesign';
17
29
  import YoutubePlayer from "react-native-youtube-iframe"
18
- import { TextInput } from 'react-native'
19
- import {
20
- Grayscale
21
- } from 'react-native-color-matrix-image-filters'
22
-
23
- import { View, TouchableOpacity, StyleSheet, Dimensions, I18nManager, SafeAreaView, Platform, Button } from 'react-native';
24
30
 
25
31
  import {
26
32
  WrapHeader,
27
33
  TopHeader,
28
- WrapContent,
29
34
  ProductTitle,
30
35
  ProductDescription,
31
36
  ProductEditions,
@@ -45,8 +50,6 @@ import { ScrollView } from 'react-native-gesture-handler';
45
50
  import { ProductOptionSubOption } from '../ProductOptionSubOption';
46
51
  import { NotFoundSource } from '../NotFoundSource';
47
52
  import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
48
- import { useState } from 'react';
49
- const windowHeight = Dimensions.get('window').height;
50
53
  const windowWidth = Dimensions.get('window').width;
51
54
 
52
55
  export const ProductOptionsUI = (props: any) => {
@@ -66,6 +69,7 @@ export const ProductOptionsUI = (props: any) => {
66
69
  handleChangeSuboptionState,
67
70
  handleChangeCommentState,
68
71
  productObject,
72
+ productAddedToCartLength
69
73
  } = props;
70
74
 
71
75
  const theme = useTheme();
@@ -151,6 +155,13 @@ export const ProductOptionsUI = (props: any) => {
151
155
  productTagNameStyle: {
152
156
  paddingHorizontal: 6,
153
157
  marginRight: 5
158
+ },
159
+ actionContainer: {
160
+ flexDirection: 'row',
161
+ alignItems: 'center',
162
+ justifyContent: 'space-between',
163
+ width: '100%',
164
+ marginTop: 10
154
165
  }
155
166
  });
156
167
 
@@ -162,7 +173,7 @@ export const ProductOptionsUI = (props: any) => {
162
173
  const [gallery, setGallery] = useState([])
163
174
  const [thumbsSwiper, setThumbsSwiper] = useState(0)
164
175
  const [indexGallery, setIndexGallery] = useState(0)
165
- const [selOpt, setSelectedOpt] = useState(0);
176
+ const [selOpt, setSelectedOpt] = useState(-1);
166
177
  const [isHaveWeight, setIsHaveWeight] = useState(false)
167
178
  const [playing, setPlaying] = useState(false);
168
179
  const [qtyBy, setQtyBy] = useState({
@@ -304,7 +315,9 @@ export const ProductOptionsUI = (props: any) => {
304
315
  selOpt == id ? theme.colors.textNormal : theme.colors.textSecondary
305
316
  }
306
317
  size={selOpt == id ? 14 : 12}
307
- weight={selOpt == id ? '600' : 'normal'}>
318
+ weight={selOpt == id ? '600' : 'normal'}
319
+ style={{ maxWidth: 150 }}
320
+ numberOfLines={1}>
308
321
  {name}
309
322
  </OText>
310
323
  </TouchableOpacity>
@@ -314,6 +327,14 @@ export const ProductOptionsUI = (props: any) => {
314
327
  </>
315
328
  );
316
329
 
330
+ const handleScroll = ({ nativeEvent: { contentOffset, layoutMeasurement } }: any) => {
331
+
332
+ const _topOption = Object.keys(optionLayout).find(((option: any) => Math.abs(contentOffset?.y - layoutMeasurement?.height - optionLayout[option]?.y) < 20))
333
+ if (_topOption) {
334
+ const _topOptionId = Number(_topOption.replace('id:', ''))
335
+ }
336
+ }
337
+
317
338
  const handleGoBack = navigation?.canGoBack()
318
339
  ? () => navigation.goBack()
319
340
  : () => navigation.navigate('Business', { store: props.businessSlug })
@@ -328,7 +349,7 @@ export const ProductOptionsUI = (props: any) => {
328
349
  useEffect(() => {
329
350
  const imageList: any = []
330
351
  const videoList: any = []
331
- product?.images && imageList.push(product.images)
352
+ product?.images?.length > 0 ? imageList.push(product.images) : imageList.push(theme?.images?.dummies?.product)
332
353
  if (product?.gallery && product?.gallery.length > 0) {
333
354
  for (const img of product?.gallery) {
334
355
  if (img?.file) {
@@ -366,693 +387,719 @@ export const ProductOptionsUI = (props: any) => {
366
387
  }
367
388
  }, [product])
368
389
 
390
+ const ActionButton = () => {
391
+ return (
392
+ <View
393
+ style={{
394
+ width: isHaveWeight ? '100%' : ((isSoldOut || maxProductQuantity <= 0) ? '60%' : '40%'),
395
+ }}>
396
+ {((productCart &&
397
+ auth &&
398
+ orderState.options?.address_id) || (isSoldOut || maxProductQuantity <= 0)) && (
399
+ <OButton
400
+ onClick={() => handleSaveProduct()}
401
+ imgRightSrc=""
402
+ text={`${orderState.loading
403
+ ? t('LOADING', 'Loading')
404
+ : (isSoldOut || maxProductQuantity <= 0)
405
+ ? t('SOLD_OUT', 'Sold out')
406
+ : editMode
407
+ ? t('UPDATE', 'Update')
408
+ : t('ADD', 'Add')
409
+ }`}
410
+ isDisabled={isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && ((productCart?.quantity + productAddedToCartLength) < product?.minimum_per_order)) || (product?.maximum_per_order && ((productCart?.quantity + productAddedToCartLength) > product?.maximum_per_order))}
411
+ textStyle={{
412
+ color: saveErrors || isSoldOut || maxProductQuantity <= 0 ? theme.colors.primary : theme.colors.white,
413
+ fontSize: orderState.loading || editMode ? 10 : 14
414
+ }}
415
+ style={{
416
+ backgroundColor: saveErrors || isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && ((productCart?.quantity + productAddedToCartLength) < product?.minimum_per_order)) || (product?.maximum_per_order && ((productCart?.quantity + productAddedToCartLength) > product?.maximum_per_order)) ? theme.colors.lightGray : theme.colors.primary,
417
+ borderColor: saveErrors || isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && ((productCart?.quantity + productAddedToCartLength) < product?.minimum_per_order)) || (product?.maximum_per_order && ((productCart?.quantity + productAddedToCartLength) > product?.maximum_per_order)) ? theme.colors.white : theme.colors.primary,
418
+ opacity: saveErrors || isSoldOut || maxProductQuantity <= 0 ? 0.3 : 1,
419
+ borderRadius: 7.6,
420
+ height: 44,
421
+ shadowOpacity: 0,
422
+ borderWidth: 1,
423
+ marginTop: isHaveWeight ? 10 : 0
424
+ }}
425
+ />
426
+ )}
427
+ {auth &&
428
+ !orderState.options?.address_id &&
429
+ (orderState.loading ? (
430
+ <OButton
431
+ isDisabled
432
+ text={t('LOADING', 'Loading')}
433
+ imgRightSrc=""
434
+ textStyle={{ fontSize: 10 }}
435
+ />
436
+ ) : (
437
+ <OButton onClick={navigation.navigate('AddressList')} />
438
+ ))}
439
+ {!auth && (
440
+ <OButton
441
+ isDisabled={isSoldOut || maxProductQuantity <= 0}
442
+ onClick={() => handleRedirectLogin()}
443
+ text={
444
+ isSoldOut || maxProductQuantity <= 0
445
+ ? t('SOLD_OUT', 'Sold out')
446
+ : t('LOGIN_SIGNUP', 'Login / Sign Up')
447
+ }
448
+ imgRightSrc=""
449
+ textStyle={{ color: theme.colors.primary, fontSize: 14 }}
450
+ style={{
451
+ height: 44,
452
+ borderColor: theme.colors.primary,
453
+ backgroundColor: theme.colors.white,
454
+ }}
455
+ />
456
+ )}
457
+ </View>
458
+ )
459
+ }
460
+
461
+ useEffect(() => {
462
+ const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
463
+ scrollViewRef.current.scrollToEnd({ animated: true })
464
+ })
465
+ return () => {
466
+ keyboardDidShowListener.remove()
467
+ }
468
+ }, [])
469
+
470
+
369
471
  return (
370
472
  <SafeAreaView style={{ flex: 1 }}>
371
473
  <TopHeader>
372
474
  <TopActions onPress={() => handleGoBack()}>
373
- <OIcon src={theme.images.general.arrow_left} width={15} />
475
+ <IconAntDesign name='arrowleft' size={26} />
374
476
  </TopActions>
375
477
  </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}
478
+ {!error && (
479
+ <ScrollView
480
+ ref={scrollViewRef}
481
+ contentContainerStyle={{ paddingBottom: 80 }}
482
+ stickyHeaderIndices={[2]}
483
+ onScroll={handleScroll}
484
+ >
485
+ <WrapHeader onLayout={(event: any) => setHeaderRefHeight(event.nativeEvent.layout?.height)}>
486
+ {loading && !product ? (
487
+ <View style={styles.productHeaderSkeleton}>
488
+ <Placeholder Animation={Fade}>
489
+ <PlaceholderLine
490
+ height={258}
491
+ style={{ borderRadius: 0 }}
492
+ width={windowWidth}
493
+ />
494
+ </Placeholder>
495
+ </View>
496
+ ) : (
497
+ <>
498
+ <Swiper
499
+ loop={false}
500
+ ref={swiperRef}
501
+ showsButtons={true}
502
+ style={styles.mainSwiper}
503
+ showsPagination={false}
504
+ onIndexChanged={(index) => handleChangeMainIndex(index)}
505
+ prevButton={
506
+ <View style={styles.swiperButton}>
507
+ <IconAntDesign
508
+ name="caretleft"
509
+ color={theme.colors.white}
510
+ size={13}
511
+ // style={styles.starIcon}
512
+ />
513
+ </View>
514
+ }
515
+ nextButton={
516
+ <View style={styles.swiperButton}>
517
+ <IconAntDesign
518
+ name="caretright"
519
+ color={theme.colors.white}
520
+ size={13}
521
+ // style={styles.starIcon}
522
+ />
523
+ </View>
524
+ }
525
+ >
526
+ {gallery && gallery.length > 0 && gallery.map((img, i) => (
527
+ <View
528
+ style={styles.slide1}
529
+ key={i}
530
+ >
531
+ {String(img).includes('image') || typeof img === 'number' ? (
532
+ <FastImage
533
+ style={{ height: '100%', opacity: isSoldOut ? 0.5 : 1, aspectRatio: 3 / 2 }}
534
+ source={typeof img !== 'number' ? {
535
+ uri: optimizeImage(img, 'h_1024,c_limit'),
536
+ priority: FastImage.priority.normal,
537
+ } : img}
416
538
  />
417
- </View>
418
- }
419
- >
420
- {gallery && gallery.length > 0 && gallery.map((img, i) => (
539
+ ) : (
540
+ <>
541
+ <YoutubePlayer
542
+ height={300}
543
+ play={playing}
544
+ videoId={img}
545
+ onChangeState={onStateChange}
546
+ />
547
+ <Button title={playing ? "pause" : "play"} onPress={togglePlaying} />
548
+ </>
549
+ )}
550
+ </View>
551
+ ))}
552
+ </Swiper>
553
+ <ScrollView
554
+ horizontal
555
+ contentContainerStyle={{
556
+ paddingHorizontal: 30,
557
+ paddingVertical: 15
558
+ }}
559
+ >
560
+ {gallery.length > 0 && gallery.map((img, index) => (
561
+ <TouchableOpacity
562
+ key={index}
563
+ onPress={() => handleClickThumb(index)}
564
+ >
421
565
  <View
422
- style={styles.slide1}
423
- key={i}
566
+ style={{
567
+ height: 56,
568
+ borderRadius: 8,
569
+ margin: 8,
570
+ opacity: index === thumbsSwiper ? 1 : 0.8
571
+ }}
424
572
  >
425
- {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,
573
+ {String(img).includes('image') ? (
574
+ <OIcon
575
+ url={img}
576
+ style={{
577
+ borderColor: theme.colors.lightGray,
578
+ borderRadius: 8,
579
+ minHeight: '100%',
580
+ opacity: isSoldOut ? 0.5 : 1
431
581
  }}
582
+ width={56}
583
+ height={56}
584
+ cover
432
585
  />
433
586
  ) : (
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
- </>
587
+ <OIcon
588
+ url={'http://img.youtube.com/vi/' + img + '/0.jpg'}
589
+ style={{
590
+ borderColor: theme.colors.lightGray,
591
+ borderRadius: 8,
592
+ minHeight: '100%',
593
+ opacity: isSoldOut ? 0.5 : 1
594
+ }}
595
+ width={56}
596
+ height={56}
597
+ cover
598
+ />
443
599
  )}
444
600
  </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>
601
+ </TouchableOpacity>
496
602
 
497
- ))}
498
- </ScrollView>
603
+ ))}
604
+ </ScrollView>
605
+ </>
606
+ )}
607
+ </WrapHeader>
608
+ <ProductSummary onLayout={(event: any) => setSummaryRefHeight(event.nativeEvent.layout?.height)}>
609
+ <ProductTitle>
610
+ {loading && !product ? (
611
+ <Placeholder Animation={Fade}>
612
+ <View
613
+ style={{
614
+ flexDirection: 'row',
615
+ justifyContent: 'space-between',
616
+ }}>
617
+ <PlaceholderLine width={40} height={20} />
618
+ <PlaceholderLine width={30} height={20} />
619
+ </View>
620
+ </Placeholder>
621
+ ) : (
622
+ <>
623
+ <View style={{ flexDirection: 'row' }}>
624
+ <OText
625
+ size={20}
626
+ lineHeight={30}
627
+ weight={'600'}
628
+ style={{ flex: 1, marginBottom: 10 }}>
629
+ {product?.name || productCart.name}
630
+ </OText>
631
+ {!!product?.calories && (
632
+ <OText size={16} style={{ color: '#808080' }}>{product?.calories} cal
633
+ </OText>
634
+ )}
635
+ </View>
636
+ {((!!product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (!!product?.estimated_person)) && (
637
+ <OText size={14} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={'#909BA9'} mBottom={7}>
638
+ {
639
+ ((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (productCart?.sku && productCart?.sku !== '-1' && productCart?.sku !== '1'))
640
+ && <>{t('SKU', 'Sku')}{' '}{product?.sku || productCart?.sku}</>
641
+ }
642
+ {product?.sku && product?.sku !== '-1' && product?.sku !== '1' && product?.estimated_person && (
643
+ <>&nbsp;&#183;&nbsp;</>
644
+ )}
645
+ {product?.estimated_person
646
+ && <>{product?.estimated_person}{' '}{t('ESTIMATED_PERSONS', 'persons')}</>
647
+ }
648
+ </OText>
649
+ )}
650
+ {isHaveWeight ? (
651
+ <OText size={16} lineHeight={24} color={theme.colors.primary}>{parsePrice(pricePerWeightUnit)} / {product?.weight_unit}</OText>
652
+ ) : (
653
+ <View style={{ flexDirection: 'row', marginBottom: 10 }}>
654
+ <OText size={16} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={theme.colors.primary}>{productCart.price ? parsePrice(productCart.price) : ''}</OText>
655
+ {product?.offer_price !== null && product?.in_offer && (
656
+ <OText style={{
657
+ fontSize: 14,
658
+ color: '#808080',
659
+ textDecorationLine: 'line-through',
660
+ marginLeft: 7,
661
+ marginRight: 7
662
+ }}>{product?.offer_price ? parsePrice(product?.offer_price) : ''}</OText>
663
+ )}
664
+ </View>
665
+ )}
499
666
  </>
500
667
  )}
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>
668
+ </ProductTitle>
669
+ <ProductDescription>
670
+ <OText color={theme.colors.textSecondary} size={12} lineHeight={18}>
671
+ {product?.description || productCart?.description}
672
+ </OText>
673
+ </ProductDescription>
674
+ <ScrollView
675
+ horizontal
676
+ showsHorizontalScrollIndicator={false}
677
+ contentContainerStyle={{ paddingBottom: 30 }}
678
+ >
679
+ {product?.tags?.map((tag: any) => (
680
+ <View
681
+ key={tag.id}
682
+ style={styles.productTagWrapper}
683
+ >
684
+ {!!tag?.image ? (
685
+ <OIcon
686
+ url={optimizeImage(tag?.image, 'h_40,c_limit')}
687
+ style={styles.productTagImageStyle}
688
+ />
516
689
  ) : (
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
- </>
690
+ <OIcon
691
+ src={theme.images?.dummies?.product}
692
+ style={styles.productTagImageStyle}
693
+ />
562
694
  )}
563
- </ProductTitle>
564
- <ProductDescription>
565
- <OText color={theme.colors.textSecondary} size={12} lineHeight={18}>
566
- {product?.description || productCart?.description}
695
+ <OText color={theme.colors.textSecondary} size={12} style={styles.productTagNameStyle}>{tag.name}</OText>
696
+ </View>
697
+ ))}
698
+ </ScrollView>
699
+ </ProductSummary>
700
+ {(!loading && product) && (
701
+ <ExtraOptionWrap
702
+ horizontal
703
+ showsHorizontalScrollIndicator={false}
704
+ style={{ marginBottom: 20 }}
705
+ contentContainerStyle={{ paddingHorizontal: 33, backgroundColor: theme.colors.white }}
706
+ >
707
+ <TouchableOpacity
708
+ key={`eopt_key_00`}
709
+ onPress={() => setSelectedOpt(-1)}
710
+ style={[
711
+ styles.extraItem,
712
+ {
713
+ borderBottomColor: selOpt == -1 ? theme.colors.textNormal : theme.colors.border,
714
+ },
715
+ ]}>
716
+ <OText
717
+ color={selOpt == -1 ? theme.colors.textNormal : theme.colors.textSecondary}
718
+ size={selOpt == -1 ? 14 : 12}
719
+ weight={selOpt == -1 ? '600' : 'normal'}>
720
+ {t('ALL', 'All')}
721
+ </OText>
722
+ </TouchableOpacity>
723
+ {product?.ingredients.length > 0 && (
724
+ <TouchableOpacity
725
+ key={`eopt_key_01`}
726
+ onPress={() => setSelectedOpt(0)}
727
+ style={[
728
+ styles.extraItem,
729
+ {
730
+ borderBottomColor:
731
+ selOpt == 0 ? theme.colors.textNormal : theme.colors.border,
732
+ },
733
+ ]}>
734
+ <OText
735
+ color={selOpt == 0 ? theme.colors.textNormal : theme.colors.textSecondary}
736
+ size={selOpt == 0 ? 14 : 12}
737
+ weight={selOpt == 0 ? '600' : 'normal'}>
738
+ {t('INGREDIENTS', 'Ingredients')}
567
739
  </OText>
568
- </ProductDescription>
569
- <ScrollView
570
- horizontal
571
- showsHorizontalScrollIndicator={false}
572
- contentContainerStyle={{ paddingBottom: 30 }}
573
- >
574
- {product?.tags?.map((tag: any) => (
740
+ </TouchableOpacity>
741
+ )}
742
+ {product?.extras.map((extra: any) =>
743
+ <ExtraOptions key={extra.id} options={extra.options} />
744
+ )}
745
+ </ExtraOptionWrap>
746
+ )}
747
+ {loading && !product ? (
748
+ <>
749
+ {[...Array(2)].map((item, i) => (
750
+ <Placeholder
751
+ key={i}
752
+ style={{ marginBottom: 20 }}
753
+ Animation={Fade}>
754
+ <PlaceholderLine
755
+ height={40}
756
+ style={{ flex: 1, marginTop: 10 }}
757
+ />
758
+ {[...Array(3)].map((item, i) => (
575
759
  <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>
760
+ key={'place_key_' + i}
761
+ style={{
762
+ flexDirection: 'row',
763
+ justifyContent: 'space-between',
764
+ }}>
765
+ <PlaceholderLine
766
+ height={30}
767
+ width={10}
768
+ style={{ marginBottom: 20 }}
769
+ />
770
+ <PlaceholderLine
771
+ height={30}
772
+ width={50}
773
+ style={{ marginBottom: 20 }}
774
+ />
775
+ <PlaceholderLine
776
+ height={30}
777
+ width={30}
778
+ style={{ marginBottom: 20 }}
779
+ />
591
780
  </View>
592
781
  ))}
593
- </ScrollView>
594
- </ProductSummary>
595
- {loading && !product ? (
782
+ </Placeholder>
783
+ ))}
784
+ </>
785
+ ) : (
786
+ <ProductEditions>
787
+ {selOpt === -1 ? (
596
788
  <>
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 }}
789
+ {product?.ingredients.length > 0 && (
790
+ <View style={styles.optionContainer} onLayout={(event: any) => handleOnLayout(event, 0)}>
791
+ <SectionTitle>
792
+ <OText size={16}>
793
+ {t('INGREDIENTS', 'Ingredients')}
794
+ </OText>
795
+ </SectionTitle>
796
+ <WrapperIngredients>
797
+ {product?.ingredients.map((ingredient: any) => (
798
+ <ProductIngredient
799
+ key={ingredient.id}
800
+ ingredient={ingredient}
801
+ state={
802
+ productCart.ingredients[`id:${ingredient.id}`]
803
+ }
804
+ onChange={handleChangeIngredientState}
805
+ isSoldOut={isSoldOut}
627
806
  />
628
- </View>
629
- ))}
630
- </Placeholder>
631
- ))}
807
+ ))}
808
+ </WrapperIngredients>
809
+ </View>
810
+ )}
811
+ {product?.extras.sort((a: any, b: any) => a.rank - b.rank).map((extra: any) =>
812
+ extra.options.sort((a: any, b: any) => a.rank - b.rank).map((option: any) => {
813
+ const currentState =
814
+ productCart.options[`id:${option.id}`] || {};
815
+ return (
816
+ <React.Fragment key={`popt_${option.id}`}>
817
+ {showOption(option) && (
818
+ <View style={styles.optionContainer} onLayout={(event: any) => handleOnLayout(event, option?.id)}>
819
+ <ProductOption
820
+ option={option}
821
+ currentState={currentState}
822
+ error={errors[`id:${option.id}`]}>
823
+ <WrapperSubOption
824
+ style={{
825
+ backgroundColor: isError(option.id),
826
+ borderRadius: 7.6
827
+ }}>
828
+ {option.suboptions.sort((a: any, b: any) => a.rank - b.rank).map(
829
+ (suboption: any) => {
830
+ const currentState =
831
+ productCart.options[
832
+ `id:${option.id}`
833
+ ]?.suboptions[
834
+ `id:${suboption.id}`
835
+ ] || {};
836
+ const balance =
837
+ productCart.options[
838
+ `id:${option.id}`
839
+ ]?.balance || 0;
840
+ return (
841
+ <ProductOptionSubOption
842
+ key={suboption.id}
843
+ isSoldOut={isSoldOut}
844
+ onChange={
845
+ handleChangeSuboptionState
846
+ }
847
+ balance={balance}
848
+ option={option}
849
+ suboption={suboption}
850
+ state={currentState}
851
+ disabled={
852
+ isSoldOut ||
853
+ maxProductQuantity <= 0
854
+ }
855
+ setIsScrollAvailable={setIsScrollAvailable}
856
+ error={errors[`id:${option.id}`]}
857
+ />
858
+ );
859
+ },
860
+ )}
861
+ </WrapperSubOption>
862
+ </ProductOption>
863
+ </View>
864
+ )}
865
+ </React.Fragment>
866
+ );
867
+ }),
868
+ )}
632
869
  </>
633
870
  ) : (
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'}>
871
+ <>
872
+ {selOpt === 0 ? (
873
+ <View style={styles.optionContainer}>
874
+ <SectionTitle>
875
+ <OText size={16}>
672
876
  {t('INGREDIENTS', 'Ingredients')}
673
877
  </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 ? (
878
+ </SectionTitle>
879
+ <WrapperIngredients>
880
+ {product?.ingredients.map((ingredient: any) => (
881
+ <ProductIngredient
882
+ key={ingredient.id}
883
+ ingredient={ingredient}
884
+ state={
885
+ productCart.ingredients[`id:${ingredient.id}`]
886
+ }
887
+ onChange={handleChangeIngredientState}
888
+ isSoldOut={isSoldOut}
889
+ />
890
+ ))}
891
+ </WrapperIngredients>
892
+ </View>
893
+ ) : (
682
894
  <>
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) =>
895
+ {product?.extras.map((extra: any) =>
706
896
  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
- );
897
+ if (
898
+ option.id == selOpt ||
899
+ (hasRespected(
900
+ extra.options,
901
+ option.respect_to,
902
+ ) &&
903
+ showOption(option))
904
+ ) {
905
+ const currentState =
906
+ productCart.options[`id:${option.id}`] || {};
907
+ return (
908
+ <React.Fragment key={option.id}>
909
+ {showOption(option) && (
910
+ <View style={styles.optionContainer}>
911
+ <ProductOption
912
+ option={option}
913
+ currentState={currentState}
914
+ error={errors[`id:${option.id}`]}>
915
+ <WrapperSubOption
916
+ style={{
917
+ backgroundColor: isError(
918
+ option.id,
919
+ ),
920
+ }}>
921
+ {option.suboptions.sort((a: any, b: any) => a.rank - b.rank).map(
922
+ (suboption: any) => {
923
+ const currentState =
924
+ productCart.options[
925
+ `id:${option.id}`
926
+ ]?.suboptions[
927
+ `id:${suboption.id}`
928
+ ] || {};
929
+ const balance =
930
+ productCart.options[
931
+ `id:${option.id}`
932
+ ]?.balance || 0;
933
+ return (
934
+ <ProductOptionSubOption
935
+ key={suboption.id}
936
+ onChange={
937
+ handleChangeSuboptionState
938
+ }
939
+ balance={balance}
940
+ option={option}
941
+ suboption={suboption}
942
+ state={currentState}
943
+ disabled={
944
+ isSoldOut ||
945
+ maxProductQuantity <= 0
946
+ }
947
+ />
948
+ );
949
+ },
950
+ )}
951
+ </WrapperSubOption>
952
+ </ProductOption>
953
+ </View>
954
+ )}
955
+ </React.Fragment>
956
+ );
957
+ }
761
958
  }),
762
959
  )}
763
960
  </>
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
961
  )}
879
- </ProductEditions>
880
- )}
881
- </WrapContent>
882
- </View>
883
- )}
884
- {!!error && error.length > 0 && (
885
- <NotFoundSource content={error[0]?.message || error[0]} />
886
- )}
887
- </ScrollView>
888
- {!loading && !error && product && (
889
- <ProductActions ios={Platform?.OS === 'ios'}>
890
- <View>
891
- <OText size={16} lineHeight={24} weight={'600'}>
892
- {productCart.total ? parsePrice(productCart?.total) : ''}
893
- </OText>
894
- {product?.minimum_per_order && productCart?.quantity < product?.minimum_per_order && <OText size={12} color={theme.colors?.red}>{t('MOBILE_MINIMUM_TO_ORDER', 'Min. _number_ ').replace('_number_', product?.minimum_per_order)}</OText>}
895
- {product?.maximum_per_order && productCart?.quantity > product?.maximum_per_order && <OText size={12} color={theme.colors?.red}>{t('MOBILE_MAXIMUM_TO_ORDER', 'Max. _number_'.replace('_number_', product?.maximum_per_order))}</OText>}
896
- </View>
897
- {productCart && !isSoldOut && maxProductQuantity > 0 && (
898
- <View style={styles.quantityControl}>
899
- <TouchableOpacity
900
- onPress={decrement}
901
- disabled={productCart.quantity === 1 || isSoldOut}>
902
- <OIcon
903
- src={theme.images.general.minus}
904
- width={16}
905
- color={
906
- productCart.quantity === 1 || isSoldOut
907
- ? theme.colors.backgroundGray
908
- : theme.colors.backgroundDark
909
- }
910
- />
911
- </TouchableOpacity>
912
- {qtyBy?.pieces && (
913
- <TextInput
914
- keyboardType='numeric'
915
- value={`${productCart?.quantity > 0 ? productCart?.quantity : ''}`}
916
- onChangeText={(val: any) => onChangeProductCartQuantity(parseInt(val))}
917
- editable={!orderState.loading}
918
- style={{
919
- borderWidth: 1,
920
- textAlign: 'center',
921
- minWidth: 60,
922
- borderRadius: 8,
923
- borderColor: theme.colors.inputBorderColor,
924
- height: 44,
925
- marginHorizontal: 10
926
- }}
927
- />
962
+ </>
928
963
  )}
929
- {qtyBy?.weight_unit && (
930
- <OText
931
- size={12}
932
- lineHeight={18}
933
- style={{ minWidth: 40, textAlign: 'center' }}
934
- >
935
- {productCart.quantity * product?.weight}
936
- </OText>
964
+ {!product?.hide_special_instructions && (
965
+ <ProductComment>
966
+ <SectionTitle>
967
+ <OText size={16} weight={'600'} lineHeight={24}>
968
+ {t('SPECIAL_COMMENT', 'Special comment')}
969
+ </OText>
970
+ </SectionTitle>
971
+ <OInput
972
+ multiline
973
+ placeholder={t('SPECIAL_COMMENT', 'Special comment')}
974
+ value={productCart.comment}
975
+ onChange={(val: string) =>
976
+ handleChangeCommentState({ target: { value: val } })
977
+ }
978
+ isDisabled={
979
+ !(productCart && !isSoldOut && maxProductQuantity)
980
+ }
981
+ style={styles.comment}
982
+ />
983
+ </ProductComment>
937
984
  )}
938
- <TouchableOpacity
939
- onPress={increment}
940
- disabled={
941
- maxProductQuantity <= 0 ||
942
- productCart.quantity >= maxProductQuantity ||
943
- isSoldOut
944
- }>
945
- <OIcon
946
- src={theme.images.general.plus}
947
- width={16}
948
- color={
949
- maxProductQuantity <= 0 ||
950
- productCart.quantity >= maxProductQuantity ||
951
- isSoldOut
952
- ? theme.colors.backgroundGray
953
- : theme.colors.backgroundDark
954
- }
955
- />
956
- </TouchableOpacity>
957
- {isHaveWeight && (
958
- <WeightUnitSwitch>
985
+ </ProductEditions>
986
+ )}
987
+ {!!error && error.length > 0 && (
988
+ <NotFoundSource content={error[0]?.message || error[0]} />
989
+ )}
990
+ </ScrollView>
991
+ )}
992
+ {!loading && !error && product && (
993
+ <ProductActions ios={Platform?.OS === 'ios'} isColumn={isHaveWeight}>
994
+ <View style={styles.actionContainer}>
995
+ <View>
996
+ <OText size={16} lineHeight={24} weight={'600'}>
997
+ {productCart.total ? parsePrice(productCart?.total) : ''}
998
+ </OText>
999
+ {product?.minimum_per_order && (productCart?.quantity + productAddedToCartLength) <= product?.minimum_per_order && productCart?.quantity !== 1 && <OText size={12} color={theme.colors?.red}>{t('MOBILE_MINIMUM_TO_ORDER', 'Min. _number_ ').replace('_number_', product?.minimum_per_order)}</OText>}
1000
+ {product?.maximum_per_order && (productCart?.quantity + productAddedToCartLength) >= product?.maximum_per_order && <OText size={12} color={theme.colors?.red}>{t('MOBILE_MAXIMUM_TO_ORDER', 'Max. _number_'.replace('_number_', product?.maximum_per_order))}</OText>}
1001
+ </View>
1002
+ {productCart && !isSoldOut && maxProductQuantity > 0 && (
1003
+ <>
1004
+ <View style={styles.quantityControl}>
959
1005
  <TouchableOpacity
960
- onPress={() => handleSwitchQtyUnit('pieces')}
961
- >
962
- <WeightUnitItem active={qtyBy?.pieces}>
963
- <OText
964
- size={12}
965
- lineHeight={18}
966
- color={qtyBy?.pieces ? theme.colors.primary : theme.colors.textNormal}
967
- >
968
- {t('PIECES', 'pcs')}
969
- </OText>
970
- </WeightUnitItem>
1006
+ onPress={decrement}
1007
+ disabled={productCart.quantity === 1 || !productCart.quantity || isSoldOut || ((productCart?.quantity + productAddedToCartLength) <= product?.minimum_per_order)}>
1008
+ <OIcon
1009
+ src={theme.images.general.minus}
1010
+ width={16}
1011
+ color={
1012
+ productCart.quantity === 1 || isSoldOut
1013
+ ? theme.colors.backgroundGray
1014
+ : theme.colors.backgroundDark
1015
+ }
1016
+ />
1017
+ </TouchableOpacity>
1018
+ {qtyBy?.pieces && (
1019
+ <TextInput
1020
+ keyboardType='numeric'
1021
+ value={`${productCart?.quantity > 0 ? productCart?.quantity : ''}`}
1022
+ onChangeText={(val: any) => onChangeProductCartQuantity(parseInt(val))}
1023
+ editable={!orderState.loading}
1024
+ style={{
1025
+ borderWidth: 1,
1026
+ textAlign: 'center',
1027
+ minWidth: 60,
1028
+ borderRadius: 8,
1029
+ borderColor: theme.colors.inputBorderColor,
1030
+ height: 44,
1031
+ marginHorizontal: 10
1032
+ }}
1033
+ />
1034
+ )}
1035
+ {qtyBy?.weight_unit && (
1036
+ <OText
1037
+ size={12}
1038
+ lineHeight={18}
1039
+ style={{ minWidth: 40, textAlign: 'center' }}
1040
+ >
1041
+ {productCart.quantity * product?.weight}
1042
+ </OText>
1043
+ )}
1044
+ <TouchableOpacity
1045
+ onPress={increment}
1046
+ disabled={
1047
+ maxProductQuantity <= 0 ||
1048
+ (productCart?.quantity + productAddedToCartLength) >= maxProductQuantity ||
1049
+ ((productCart?.quantity + productAddedToCartLength) >= product?.maximum_per_order && product?.maximum_per_order) ||
1050
+ isSoldOut
1051
+ }>
1052
+ <OIcon
1053
+ src={theme.images.general.plus}
1054
+ width={16}
1055
+ color={
1056
+ maxProductQuantity <= 0 ||
1057
+ (productCart?.quantity + productAddedToCartLength) >= maxProductQuantity ||
1058
+ ((productCart?.quantity + productAddedToCartLength) >= product?.maximum_per_order && product?.maximum_per_order) ||
1059
+ isSoldOut
1060
+ ? theme.colors.backgroundGray
1061
+ : theme.colors.backgroundDark
1062
+ }
1063
+ />
971
1064
  </TouchableOpacity>
972
- <View style={{ alignItems: 'flex-start' }}>
1065
+ </View>
1066
+ {isHaveWeight && (
1067
+ <WeightUnitSwitch>
973
1068
  <TouchableOpacity
974
- onPress={() => handleSwitchQtyUnit('weight_unit')}
1069
+ onPress={() => handleSwitchQtyUnit('pieces')}
975
1070
  >
976
- <WeightUnitItem active={qtyBy?.weight_unit}>
1071
+ <WeightUnitItem active={qtyBy?.pieces}>
977
1072
  <OText
978
1073
  size={12}
979
1074
  lineHeight={18}
980
- color={qtyBy?.weight_unit ? theme.colors.primary : theme.colors.textNormal}
1075
+ color={qtyBy?.pieces ? theme.colors.primary : theme.colors.textNormal}
981
1076
  >
982
- {product?.weight_unit}
1077
+ {t('PIECES', 'pcs')}
983
1078
  </OText>
984
1079
  </WeightUnitItem>
985
1080
  </TouchableOpacity>
986
- </View>
987
- </WeightUnitSwitch>
988
- )}
989
- </View>
990
- )}
991
- <View
992
- style={{
993
- width: isSoldOut || maxProductQuantity <= 0 ? '60%' : '40%',
994
- }}>
995
- {((productCart &&
996
- auth &&
997
- orderState.options?.address_id) || (isSoldOut || maxProductQuantity <= 0)) && (
998
- <OButton
999
- onClick={() => handleSaveProduct()}
1000
- imgRightSrc=""
1001
- text={`${orderState.loading
1002
- ? t('LOADING', 'Loading')
1003
- : (isSoldOut || maxProductQuantity <= 0)
1004
- ? t('SOLD_OUT', 'Sold out')
1005
- : editMode
1006
- ? t('UPDATE', 'Update')
1007
- : t('ADD', 'Add')
1008
- }`}
1009
- isDisabled={isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && (productCart?.quantity < product?.minimum_per_order)) || (product?.maximum_per_order && (productCart?.quantity > product?.maximum_per_order))}
1010
- textStyle={{
1011
- color: saveErrors || isSoldOut || maxProductQuantity <= 0 ? theme.colors.primary : theme.colors.white,
1012
- fontSize: orderState.loading || editMode ? 10 : 14
1013
- }}
1014
- style={{
1015
- backgroundColor: saveErrors || isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && (productCart?.quantity < product?.minimum_per_order)) || (product?.maximum_per_order && (productCart?.quantity > product?.maximum_per_order)) ? theme.colors.lightGray : theme.colors.primary,
1016
- borderColor: saveErrors || isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && (productCart?.quantity < product?.minimum_per_order)) || (product?.maximum_per_order && (productCart?.quantity > product?.maximum_per_order)) ? theme.colors.white : theme.colors.primary,
1017
- opacity: saveErrors || isSoldOut || maxProductQuantity <= 0 ? 0.3 : 1,
1018
- borderRadius: 7.6,
1019
- height: 44,
1020
- shadowOpacity: 0,
1021
- borderWidth: 1,
1022
- }}
1023
- />
1024
- )}
1025
- {auth &&
1026
- !orderState.options?.address_id &&
1027
- (orderState.loading ? (
1028
- <OButton
1029
- isDisabled
1030
- text={t('LOADING', 'Loading')}
1031
- imgRightSrc=""
1032
- textStyle={{ fontSize: 10 }}
1033
- />
1034
- ) : (
1035
- <OButton onClick={navigation.navigate('AddressList')} />
1036
- ))}
1037
- {!auth && (
1038
- <OButton
1039
- isDisabled={isSoldOut || maxProductQuantity <= 0}
1040
- onClick={() => handleRedirectLogin()}
1041
- text={
1042
- isSoldOut || maxProductQuantity <= 0
1043
- ? t('SOLD_OUT', 'Sold out')
1044
- : t('LOGIN_SIGNUP', 'Login / Sign Up')
1045
- }
1046
- imgRightSrc=""
1047
- textStyle={{ color: theme.colors.primary, fontSize: 14 }}
1048
- style={{
1049
- height: 44,
1050
- borderColor: theme.colors.primary,
1051
- backgroundColor: theme.colors.white,
1052
- }}
1053
- />
1081
+ <View style={{ alignItems: 'flex-start' }}>
1082
+ <TouchableOpacity
1083
+ onPress={() => handleSwitchQtyUnit('weight_unit')}
1084
+ >
1085
+ <WeightUnitItem active={qtyBy?.weight_unit}>
1086
+ <OText
1087
+ size={12}
1088
+ lineHeight={18}
1089
+ color={qtyBy?.weight_unit ? theme.colors.primary : theme.colors.textNormal}
1090
+ >
1091
+ {product?.weight_unit}
1092
+ </OText>
1093
+ </WeightUnitItem>
1094
+ </TouchableOpacity>
1095
+ </View>
1096
+ </WeightUnitSwitch>
1097
+ )}
1098
+ </>
1054
1099
  )}
1100
+ {!isHaveWeight && <ActionButton />}
1055
1101
  </View>
1102
+ {isHaveWeight && <ActionButton />}
1056
1103
  </ProductActions>
1057
1104
  )}
1058
1105
  </SafeAreaView>
@@ -1061,10 +1108,20 @@ export const ProductOptionsUI = (props: any) => {
1061
1108
 
1062
1109
 
1063
1110
  export const ProductForm = (props: any) => {
1064
- const productOptionsProps = {
1065
- ...props,
1066
- UIComponent: ProductOptionsUI,
1067
- };
1111
+ const productOptionsProps = {
1112
+ ...props,
1113
+ productCart: {
1114
+ ...props.productCart,
1115
+ quantity: props.productCart?.code
1116
+ ? props.productCart?.quantity
1117
+ : props?.product?.minimum_per_order || 1
1118
+ },
1119
+ UIComponent: ProductOptionsUI
1120
+ }
1068
1121
 
1069
- return <ProductOptions {...productOptionsProps} />;
1122
+ return <ProductOptions {...productOptionsProps} />
1070
1123
  };
1124
+
1125
+ ProductForm.defaultProps = {
1126
+ productAddedToCartLength: 0
1127
+ }