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