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