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