ordering-ui-react-native 0.14.25 → 0.14.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ordering-ui-react-native",
3
- "version": "0.14.25",
3
+ "version": "0.14.29",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -70,6 +70,7 @@
70
70
  "react-native-bootsplash": "^3.2.3",
71
71
  "react-native-calendar-picker": "^7.1.2",
72
72
  "react-native-calendar-strip": "^2.2.5",
73
+ "react-native-color-matrix-image-filters": "^5.2.10",
73
74
  "react-native-country-picker-modal": "^2.0.0",
74
75
  "react-native-credit-card-input": "^0.4.1",
75
76
  "react-native-document-picker": "^5.2.0",
@@ -150,10 +150,10 @@ const CheckoutUI = (props: any) => {
150
150
  const isPreOrderSetting = configs?.preorder_status_enabled?.value === '1'
151
151
  const cartsWithProducts = carts && Object.values(carts).filter((cart: any) => cart.products.length) || null
152
152
 
153
- const deliveryOptions = instructionsOptions?.result && instructionsOptions?.result?.filter((option: any) => option?.enabled)?.map(option => {
153
+ const deliveryOptions = instructionsOptions?.result && instructionsOptions?.result?.filter((option: any) => option?.enabled)?.map((option: any) => {
154
154
  return {
155
- value: option?.id, key: option?.id, label: option?.name
156
- }
155
+ value: option?.id, key: option?.id, label: t(option?.name.toUpperCase().replace(/\s/g, '_'), option?.name)
156
+ }
157
157
  })
158
158
 
159
159
  const handlePlaceOrder = () => {
@@ -45,6 +45,7 @@ const imgOptions = {
45
45
  includeBase64: true,
46
46
  selectionLimit: 0
47
47
  }
48
+ const filterSpecialStatus = ['prepared_in', 'delivered_in']
48
49
 
49
50
  const MessagesUI = (props: MessagesParams) => {
50
51
  const {
@@ -118,7 +119,11 @@ const MessagesUI = (props: MessagesParams) => {
118
119
  const messageConsole = (message: any) => {
119
120
  return message.change?.attribute !== 'driver_id'
120
121
  ?
121
- `${t('ORDER', 'Order')} ${t(message.change.attribute.toUpperCase(), message.change.attribute.replace('_', ' '))} ${t('CHANGED_FROM', 'Changed from')} ${message.change.old !== null && t(ORDER_STATUS[parseInt(message.change.old, 10)])} ${t('TO', 'to')} ${t(ORDER_STATUS[parseInt(message.change.new, 10)])}`
122
+ `${t('ORDER', 'Order')} ${t(message.change.attribute.toUpperCase(), message.change.attribute.replace('_', ' '))} ${t('CHANGED_FROM', 'Changed from')} ${
123
+ filterSpecialStatus.includes(message.change.attribute) ?
124
+ `${message.change.old === null ? '0' : message.change.old} ${t('TO', 'to')} ${message.change.new} ${t('MINUTES', 'Minutes')}` :
125
+ `${message.change.old !== null && t(ORDER_STATUS[parseInt(message.change.old, 10)])} ${t('TO', 'to')} ${t(ORDER_STATUS[parseInt(message.change.new, 10)])}`
126
+ }`
122
127
  : message.change.new
123
128
  ?
124
129
  `${message.driver?.name} ${message.driver?.lastname !== null ? message.driver.lastname : ''} ${t('WAS_ASSIGNED_AS_DRIVER', 'Was assigned as driver')} ${message.comment ? message.comment.length : ''}`
@@ -9,16 +9,19 @@ import {
9
9
  BIInfo,
10
10
  BIContentInfo,
11
11
  BITotal,
12
- BIActions
12
+ BIActions,
13
+ PriceContainer
13
14
  } from './styles';
14
- import { OAlert, OIcon, OText } from '../shared';
15
+ import { OAlert, OButton, OIcon, OText } from '../shared';
15
16
 
16
17
  export const BusinessItemAccordion = (props: any) => {
17
18
  const {
18
19
  cart,
19
20
  moment,
20
- singleBusiness,
21
- handleClearProducts
21
+ singleBusiness,
22
+ handleClearProducts,
23
+ handleClickCheckout,
24
+ checkoutButtonDisabled
22
25
  } = props
23
26
 
24
27
  const [orderState] = useOrder();
@@ -41,7 +44,7 @@ export const BusinessItemAccordion = (props: any) => {
41
44
  }, [orderState?.carts])
42
45
 
43
46
  return (
44
- <BIContainer isClosed={isClosed}>
47
+ <BIContainer isClosed={isClosed} checkoutVisible={!isActive && !isClosed && !!isProducts && !checkoutButtonDisabled}>
45
48
  <BIHeader
46
49
  isClosed={isClosed}
47
50
  onPress={() => !isClosed ? setActiveState(!isActive) : isClosed}
@@ -71,37 +74,39 @@ export const BusinessItemAccordion = (props: any) => {
71
74
  {props.onNavigationRedirect && !isClosed && (
72
75
  <>
73
76
  <TouchableOpacity onPress={() => props.onNavigationRedirect('Business', { store: cart?.business?.slug })}>
74
- <OText color={theme.colors.textSecondary} size={12} lineHeight={18} style={{ textDecorationLine: 'underline' }}>{t('GO_TO_STORE', 'Go to store')}</OText>
77
+ <OText color={theme.colors.primary} size={12} lineHeight={18} style={{ textDecorationLine: 'underline' }}>{t('GO_TO_STORE', 'Go to store')}</OText>
75
78
  </TouchableOpacity>
76
- <OText color={theme.colors.textSecondary}>{' \u2022 '}</OText>
77
79
  </>
78
80
  )}
79
81
  {!isCartPending && !isClosed && (
80
- <OAlert
81
- title={t('DELETE_CART', 'Delete Cart')}
82
- message={t('QUESTION_DELETE_CART', 'Are you sure to you wants delete the selected cart')}
83
- onAccept={() => handleClearProducts()}
84
- >
85
- <OText size={12} lineHeight={18} color={theme.colors.textSecondary} style={{ textDecorationLine: 'underline' }}>{t('CLEAR_CART', 'Clear cart')}</OText>
86
- </OAlert>
82
+ <>
83
+ <OText color={theme.colors.textSecondary}>{' \u2022 '}</OText>
84
+ <OAlert
85
+ title={t('DELETE_CART', 'Delete Cart')}
86
+ message={t('QUESTION_DELETE_CART', 'Are you sure to you wants delete the selected cart')}
87
+ onAccept={() => handleClearProducts()}
88
+ >
89
+ <OText size={12} lineHeight={18} color={theme.colors.primary} style={{ textDecorationLine: 'underline' }}>{t('CLEAR_CART', 'Clear cart')}</OText>
90
+ </OAlert>
91
+ </>
92
+ )}
93
+ {props.handleChangeStore && (
94
+ <>
95
+ <OText color={theme.colors.textSecondary}>{' \u2022 '}</OText>
96
+ <TouchableOpacity
97
+ onPress={props.handleChangeStore}
98
+ >
99
+ <OText
100
+ size={12}
101
+ lineHeight={18}
102
+ color={theme.colors.textSecondary}
103
+ style={{ textDecorationLine: 'underline' }}
104
+ >
105
+ {t('CHANGE_STORE', 'Change store')}
106
+ </OText>
107
+ </TouchableOpacity>
108
+ </>
87
109
  )}
88
- {props.handleChangeStore && (
89
- <>
90
- <OText color={theme.colors.textSecondary}>{' \u2022 '}</OText>
91
- <TouchableOpacity
92
- onPress={props.handleChangeStore}
93
- >
94
- <OText
95
- size={12}
96
- lineHeight={18}
97
- color={theme.colors.textSecondary}
98
- style={{ textDecorationLine: 'underline' }}
99
- >
100
- {t('CHANGE_STORE', 'Change store')}
101
- </OText>
102
- </TouchableOpacity>
103
- </>
104
- )}
105
110
  </View>
106
111
  </BIContentInfo>
107
112
  </BIInfo>
@@ -134,6 +139,19 @@ export const BusinessItemAccordion = (props: any) => {
134
139
  )}
135
140
  </BIActions>
136
141
  </BIHeader>
142
+ {!isActive && !isClosed && !!isProducts && !checkoutButtonDisabled && (
143
+ <PriceContainer>
144
+ <OText>{parsePrice(cart?.total)}</OText>
145
+ <OButton
146
+ onClick={handleClickCheckout}
147
+ textStyle={{ color: 'white', textAlign: 'center', flex: 1 }}
148
+ style={{ width: 160, flexDirection: 'row', justifyContent: 'center', borderRadius: 7.6, shadowOpacity: 0 }}
149
+ text={t('CHECKOUT', 'Checkout')}
150
+ bgColor={(cart?.subtotal < cart?.minimum || !cart?.valid_address) ? theme.colors.secundary : theme.colors.primary}
151
+ borderColor={theme.colors.primary}
152
+ />
153
+ </PriceContainer>
154
+ )}
137
155
 
138
156
  <BIContent style={{ display: isActive ? 'flex' : 'none' }}>
139
157
  {props.children}
@@ -52,3 +52,10 @@ export const BIActions = styled.View`
52
52
  align-items: center;
53
53
  justify-content: flex-end;
54
54
  `
55
+
56
+ export const PriceContainer = styled.View`
57
+ flex-direction: row;
58
+ justify-content: space-between;
59
+ align-items: center;
60
+ flex: 1
61
+ `
@@ -42,7 +42,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
42
42
  return (
43
43
  <ProductsContainer>
44
44
  {category.id &&
45
- categoryState.products?.map((product: any) => (
45
+ categoryState.products?.sort((a: any, b: any) => a.rank - b.rank).map((product: any) => (
46
46
  <SingleProductCard
47
47
  key={'prod_' + product.id}
48
48
  isSoldOut={product.inventoried && !product.quantity}
@@ -63,7 +63,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
63
63
  {t('FEATURED', 'Featured')}
64
64
  </OText>
65
65
  <>
66
- {categoryState.products?.map(
66
+ {categoryState.products?.sort((a: any, b: any) => a.rank - b.rank).map(
67
67
  (product: any, i: any) =>
68
68
  product.featured && (
69
69
  <SingleProductCard
@@ -110,7 +110,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
110
110
  </OText>
111
111
  </View>
112
112
  <>
113
- {products.map((product: any, i: any) => (
113
+ {products.sort((a: any, b: any) => a.rank - b.rank).map((product: any, i: any) => (
114
114
  <SingleProductCard
115
115
  key={i}
116
116
  isSoldOut={product.inventoried && !product.quantity}
@@ -145,6 +145,8 @@ const CartUI = (props: any) => {
145
145
  handleCartOpen={handleCartOpen}
146
146
  onNavigationRedirect={props.onNavigationRedirect}
147
147
  handleChangeStore={props.isFranchiseApp ? () => setOpenChangeStore(true) : null}
148
+ handleClickCheckout={() => setOpenUpselling(true)}
149
+ checkoutButtonDisabled={(openUpselling && !canOpenUpselling) || cart?.subtotal < cart?.minimum || !cart?.valid_address}
148
150
  >
149
151
  {cart?.products?.length > 0 && cart?.products.map((product: any) => (
150
152
  <ProductItemAccordion
@@ -137,7 +137,7 @@ const CheckoutUI = (props: any) => {
137
137
 
138
138
  const deliveryOptions = instructionsOptions?.result && instructionsOptions?.result?.filter((option: any) => option?.enabled)?.map((option: any) => {
139
139
  return {
140
- value: option?.id, key: option?.id, label: option?.name
140
+ value: option?.id, key: option?.id, label: t(option?.name.toUpperCase().replace(/\s/g, '_'), option?.name)
141
141
  }
142
142
  })
143
143
 
@@ -12,6 +12,34 @@ import { MessagesParams } from '../../types'
12
12
  import { useWindowDimensions } from 'react-native'
13
13
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
14
14
 
15
+ const ORDER_STATUS: any = {
16
+ 0: 'ORDER_STATUS_PENDING',
17
+ 1: 'ORDERS_COMPLETED',
18
+ 2: 'ORDER_REJECTED',
19
+ 3: 'ORDER_STATUS_IN_BUSINESS',
20
+ 4: 'ORDER_READY',
21
+ 5: 'ORDER_REJECTED_RESTAURANT',
22
+ 6: 'ORDER_STATUS_CANCELLEDBYDRIVER',
23
+ 7: 'ORDER_STATUS_ACCEPTEDBYRESTAURANT',
24
+ 8: 'ORDER_CONFIRMED_ACCEPTED_BY_DRIVER',
25
+ 9: 'ORDER_PICKUP_COMPLETED_BY_DRIVER',
26
+ 10: 'ORDER_PICKUP_FAILED_BY_DRIVER',
27
+ 11: 'ORDER_DELIVERY_COMPLETED_BY_DRIVER',
28
+ 12: 'ORDER_DELIVERY_FAILED_BY_DRIVER',
29
+ 13: 'PREORDER',
30
+ 14: 'ORDER_NOT_READY',
31
+ 15: 'ORDER_PICKEDUP_COMPLETED_BY_CUSTOMER',
32
+ 16: 'ORDER_STATUS_CANCELLED_BY_CUSTOMER',
33
+ 17: 'ORDER_NOT_PICKEDUP_BY_CUSTOMER',
34
+ 18: 'ORDER_DRIVER_ALMOST_ARRIVED_BUSINESS',
35
+ 19: 'ORDER_DRIVER_ALMOST_ARRIVED_CUSTOMER',
36
+ 20: 'ORDER_CUSTOMER_ALMOST_ARRIVED_BUSINESS',
37
+ 21: 'ORDER_CUSTOMER_ARRIVED_BUSINESS',
38
+ }
39
+
40
+ const filterSpecialStatus = ['prepared_in', 'delivered_in']
41
+
42
+
15
43
  const MessagesUI = (props: MessagesParams) => {
16
44
  const {
17
45
  type,
@@ -94,58 +122,6 @@ const MessagesUI = (props: MessagesParams) => {
94
122
  });
95
123
  };
96
124
 
97
- const getStatus = (status: number) => {
98
-
99
- switch (status) {
100
- case 0:
101
- return 'ORDER_STATUS_PENDING'
102
- case 1:
103
- return 'ORDERS_COMPLETED'
104
- case 2:
105
- return 'ORDER_REJECTED'
106
- case 3:
107
- return 'ORDER_STATUS_IN_BUSINESS'
108
- case 4:
109
- return 'ORDER_READY'
110
- case 5:
111
- return 'ORDER_REJECTED_RESTAURANT'
112
- case 6:
113
- return 'ORDER_STATUS_CANCELLEDBYDRIVER'
114
- case 7:
115
- return 'ORDER_STATUS_ACCEPTEDBYRESTAURANT'
116
- case 8:
117
- return 'ORDER_CONFIRMED_ACCEPTED_BY_DRIVER'
118
- case 9:
119
- return 'ORDER_PICKUP_COMPLETED_BY_DRIVER'
120
- case 10:
121
- return 'ORDER_PICKUP_FAILED_BY_DRIVER'
122
- case 11:
123
- return 'ORDER_DELIVERY_COMPLETED_BY_DRIVER'
124
- case 12:
125
- return 'ORDER_DELIVERY_FAILED_BY_DRIVER'
126
- case 13:
127
- return 'PREORDER'
128
- case 14:
129
- return 'ORDER_NOT_READY'
130
- case 15:
131
- return 'ORDER_PICKEDUP_COMPLETED_BY_CUSTOMER'
132
- case 16:
133
- return 'ORDER_STATUS_CANCELLED_BY_CUSTOMER'
134
- case 17:
135
- return 'ORDER_NOT_PICKEDUP_BY_CUSTOMER'
136
- case 18:
137
- return 'ORDER_DRIVER_ALMOST_ARRIVED_BUSINESS'
138
- case 19:
139
- return 'ORDER_DRIVER_ALMOST_ARRIVED_CUSTOMER'
140
- case 20:
141
- return 'ORDER_CUSTOMER_ALMOST_ARRIVED_BUSINESS'
142
- case 21:
143
- return 'ORDER_CUSTOMER_ARRIVED_BUSINESS'
144
- default:
145
- return status
146
- }
147
- }
148
-
149
125
  const onSubmit = (values: any) => {
150
126
  handleSend && handleSend()
151
127
  setImage && setImage(null)
@@ -154,14 +130,18 @@ const MessagesUI = (props: MessagesParams) => {
154
130
 
155
131
  const messageConsole = (message: any) => {
156
132
  return message.change?.attribute !== 'driver_id'
133
+ ?
134
+ `${t('ORDER', 'Order')} ${t(message.change.attribute.toUpperCase(), message.change.attribute.replace('_', ' '))} ${t('CHANGED_FROM', 'Changed from')} ${
135
+ filterSpecialStatus.includes(message.change.attribute) ?
136
+ `${message.change.old === null ? '0' : message.change.old} ${t('TO', 'to')} ${message.change.new} ${t('MINUTES', 'Minutes')}` :
137
+ `${message.change.old !== null && t(ORDER_STATUS[parseInt(message.change.old, 10)])} ${t('TO', 'to')} ${t(ORDER_STATUS[parseInt(message.change.new, 10)])}`
138
+ }`
139
+ : message.change.new
157
140
  ?
158
- `${t('ORDER', 'Order')} ${message.change.attribute} ${t('CHANGED_FROM', 'Changed from')} ${message.change.old !== null && t(getStatus(parseInt(message.change.old, 10)))} ${t('TO', 'to')} ${t(getStatus(parseInt(message.change.new, 10)))}`
159
- : message.change.new
160
- ?
161
- `${message.driver?.name} ${message.driver?.lastname !== null ? message.driver.lastname : ''} ${t('WAS_ASSIGNED_AS_DRIVER', 'Was assigned as driver')} ${message.comment ? message.comment.length : ''}`
162
- :
163
- `${t('DRIVER_UNASSIGNED', 'Driver unassigned')}`
164
- }
141
+ `${message.driver?.name} ${message.driver?.lastname !== null ? message.driver.lastname : ''} ${t('WAS_ASSIGNED_AS_DRIVER', 'Was assigned as driver')} ${message.comment ? message.comment.length : ''}`
142
+ :
143
+ `${t('DRIVER_UNASSIGNED', 'Driver unassigned')}`
144
+ }
165
145
 
166
146
  useEffect(() => {
167
147
  let newMessages: Array<any> = []
@@ -894,6 +894,8 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
894
894
  orderId={order?.id}
895
895
  messages={messages}
896
896
  order={order}
897
+ business={openModalForBusiness}
898
+ driver={openModalForDriver}
897
899
  setMessages={setMessages}
898
900
  onClose={handleCloseModal}
899
901
  />
@@ -12,6 +12,9 @@ import { ProductOption } from '../ProductOption';
12
12
  import Swiper from 'react-native-swiper'
13
13
  import FastImage from 'react-native-fast-image';
14
14
  import IconAntDesign from 'react-native-vector-icons/AntDesign';
15
+ import {
16
+ Grayscale
17
+ } from 'react-native-color-matrix-image-filters'
15
18
 
16
19
  import { View, TouchableOpacity, StyleSheet, Dimensions, Platform, AppRegistry, I18nManager } from 'react-native';
17
20
 
@@ -28,7 +31,9 @@ import {
28
31
  WrapperSubOption,
29
32
  ProductComment,
30
33
  ProductActions,
31
- ExtraOptionWrap
34
+ ExtraOptionWrap,
35
+ WeightUnitSwitch,
36
+ WeightUnitItem
32
37
  } from './styles';
33
38
  import { OButton, OIcon, OInput, OText } from '../shared';
34
39
  import { ScrollView } from 'react-native-gesture-handler';
@@ -127,6 +132,9 @@ export const ProductOptionsUI = (props: any) => {
127
132
  height: 32,
128
133
  borderRadius: 16,
129
134
  backgroundColor: 'rgba(208,208,208,0.5)'
135
+ },
136
+ unitItem: {
137
+ fontSize: 12
130
138
  }
131
139
  });
132
140
 
@@ -141,6 +149,12 @@ export const ProductOptionsUI = (props: any) => {
141
149
  const { top, bottom } = useSafeAreaInsets();
142
150
  const { height } = useWindowDimensions();
143
151
  const [selOpt, setSelectedOpt] = useState(0);
152
+ const [isHaveWeight, setIsHaveWeight] = useState(false)
153
+ const [qtyBy, setQtyBy] = useState({
154
+ weight_unit: false,
155
+ pieces: true
156
+ })
157
+ const [pricePerWeightUnit, setPricePerWeightUnit] = useState(null)
144
158
 
145
159
  const swiperRef: any = useRef(null)
146
160
 
@@ -149,9 +163,12 @@ export const ProductOptionsUI = (props: any) => {
149
163
  if (errors[`id:${id}`]) {
150
164
  bgColor = 'rgba(255, 0, 0, 0.05)';
151
165
  }
152
- if (isSoldOut || maxProductQuantity <= 0) {
166
+ if (maxProductQuantity <= 0) {
153
167
  bgColor = 'hsl(0, 0%, 72%)';
154
168
  }
169
+ if (isSoldOut) {
170
+ bgColor = theme.colors.white;
171
+ }
155
172
  return bgColor;
156
173
  };
157
174
 
@@ -193,6 +210,10 @@ export const ProductOptionsUI = (props: any) => {
193
210
  navigation.navigate('Login');
194
211
  };
195
212
 
213
+ const handleSwitchQtyUnit = (val: string) => {
214
+ setQtyBy({ [val]: true, [!val]: false })
215
+ }
216
+
196
217
  useEffect(() => {
197
218
  const productImgList: any = []
198
219
  product?.images && productImgList.push(product.images)
@@ -202,6 +223,11 @@ export const ProductOptionsUI = (props: any) => {
202
223
  }
203
224
  }
204
225
  setGallery(productImgList)
226
+
227
+ if (product?.weight && product?.weight_unit) {
228
+ setIsHaveWeight(true)
229
+ setPricePerWeightUnit(product?.price / product?.weight)
230
+ }
205
231
  }, [product])
206
232
 
207
233
  const saveErrors =
@@ -316,13 +342,15 @@ export const ProductOptionsUI = (props: any) => {
316
342
  style={styles.slide1}
317
343
  key={i}
318
344
  >
319
- <FastImage
320
- style={{ height: '100%' }}
321
- source={{
322
- uri: optimizeImage(img, 'h_258,c_limit'),
323
- priority: FastImage.priority.normal,
324
- }}
325
- />
345
+ <Grayscale amount={isSoldOut ? 1 : 0}>
346
+ <FastImage
347
+ style={{ height: '100%' }}
348
+ source={{
349
+ uri: optimizeImage(img, 'h_258,c_limit'),
350
+ priority: FastImage.priority.normal,
351
+ }}
352
+ />
353
+ </Grayscale>
326
354
  </View>
327
355
  ))}
328
356
  </Swiper>
@@ -346,17 +374,19 @@ export const ProductOptionsUI = (props: any) => {
346
374
  opacity: index === thumbsSwiper ? 1 : 0.8
347
375
  }}
348
376
  >
349
- <OIcon
350
- url={img}
351
- style={{
352
- borderColor: theme.colors.lightGray,
353
- borderRadius: 8,
354
- minHeight: '100%'
355
- }}
356
- width={56}
357
- height={56}
358
- cover
359
- />
377
+ <Grayscale amount={isSoldOut ? 1 : 0}>
378
+ <OIcon
379
+ url={img}
380
+ style={{
381
+ borderColor: theme.colors.lightGray,
382
+ borderRadius: 8,
383
+ minHeight: '100%'
384
+ }}
385
+ width={56}
386
+ height={56}
387
+ cover
388
+ />
389
+ </Grayscale>
360
390
  </View>
361
391
  </TouchableOpacity>
362
392
 
@@ -401,9 +431,13 @@ export const ProductOptionsUI = (props: any) => {
401
431
  }
402
432
  </OText>
403
433
  )}
404
- <OText size={16} lineHeight={24} color={theme.colors.textNormal}>
405
- {productCart.price ? parsePrice(productCart.price) : ''}
406
- </OText>
434
+ {isHaveWeight ? (
435
+ <OText size={16} lineHeight={24} color={theme.colors.textNormal}>{parsePrice(pricePerWeightUnit)} / {product?.weight_unit}</OText>
436
+ ) : (
437
+ <OText size={16} lineHeight={24} color={theme.colors.textNormal}>
438
+ {productCart.price ? parsePrice(productCart.price) : ''}
439
+ </OText>
440
+ )}
407
441
  </>
408
442
  )}
409
443
  </ProductTitle>
@@ -488,13 +522,7 @@ export const ProductOptionsUI = (props: any) => {
488
522
  {t('INGREDIENTS', 'Ingredients')}
489
523
  </OText>
490
524
  </SectionTitle>
491
- <WrapperIngredients
492
- style={{
493
- backgroundColor:
494
- isSoldOut || maxProductQuantity <= 0
495
- ? 'hsl(0, 0%, 72%)'
496
- : theme.colors.white,
497
- }}>
525
+ <WrapperIngredients>
498
526
  {product?.ingredients.map((ingredient: any) => (
499
527
  <ProductIngredient
500
528
  key={ingredient.id}
@@ -503,6 +531,7 @@ export const ProductOptionsUI = (props: any) => {
503
531
  productCart.ingredients[`id:${ingredient.id}`]
504
532
  }
505
533
  onChange={handleChangeIngredientState}
534
+ isSoldOut={isSoldOut}
506
535
  />
507
536
  ))}
508
537
  </WrapperIngredients>
@@ -540,6 +569,7 @@ export const ProductOptionsUI = (props: any) => {
540
569
  return (
541
570
  <ProductOptionSubOption
542
571
  key={suboption.id}
572
+ isSoldOut={isSoldOut}
543
573
  onChange={
544
574
  handleChangeSuboptionState
545
575
  }
@@ -573,13 +603,7 @@ export const ProductOptionsUI = (props: any) => {
573
603
  {t('INGREDIENTS', 'Ingredients')}
574
604
  </OText>
575
605
  </SectionTitle>
576
- <WrapperIngredients
577
- style={{
578
- backgroundColor:
579
- isSoldOut || maxProductQuantity <= 0
580
- ? 'hsl(0, 0%, 72%)'
581
- : theme.colors.white,
582
- }}>
606
+ <WrapperIngredients>
583
607
  {product?.ingredients.map((ingredient: any) => (
584
608
  <ProductIngredient
585
609
  key={ingredient.id}
@@ -588,6 +612,7 @@ export const ProductOptionsUI = (props: any) => {
588
612
  productCart.ingredients[`id:${ingredient.id}`]
589
613
  }
590
614
  onChange={handleChangeIngredientState}
615
+ isSoldOut={isSoldOut}
591
616
  />
592
617
  ))}
593
618
  </WrapperIngredients>
@@ -720,8 +745,10 @@ export const ProductOptionsUI = (props: any) => {
720
745
  <OText
721
746
  size={12}
722
747
  lineHeight={18}
723
- style={{ minWidth: 29, textAlign: 'center' }}>
724
- {productCart.quantity}
748
+ style={{ minWidth: 29, textAlign: 'center' }}
749
+ >
750
+ {qtyBy?.pieces && productCart.quantity}
751
+ {qtyBy?.weight_unit && productCart.quantity * product?.weight}
725
752
  </OText>
726
753
  <TouchableOpacity
727
754
  onPress={increment}
@@ -742,6 +769,36 @@ export const ProductOptionsUI = (props: any) => {
742
769
  }
743
770
  />
744
771
  </TouchableOpacity>
772
+ <WeightUnitSwitch>
773
+ <TouchableOpacity
774
+ onPress={() => handleSwitchQtyUnit('pieces')}
775
+ >
776
+ <WeightUnitItem active={qtyBy?.pieces}>
777
+ <OText
778
+ size={12}
779
+ lineHeight={18}
780
+ color={qtyBy?.pieces ? theme.colors.primary : theme.colors.textNormal}
781
+ >
782
+ {t('PIECES', 'pieces')}
783
+ </OText>
784
+ </WeightUnitItem>
785
+ </TouchableOpacity>
786
+ <View style={{ alignItems: 'flex-start' }}>
787
+ <TouchableOpacity
788
+ onPress={() => handleSwitchQtyUnit('weight_unit')}
789
+ >
790
+ <WeightUnitItem active={qtyBy?.weight_unit}>
791
+ <OText
792
+ size={12}
793
+ lineHeight={18}
794
+ color={qtyBy?.weight_unit ? theme.colors.primary : theme.colors.textNormal}
795
+ >
796
+ {product?.weight_unit}
797
+ </OText>
798
+ </WeightUnitItem>
799
+ </TouchableOpacity>
800
+ </View>
801
+ </WeightUnitSwitch>
745
802
  </View>
746
803
  )}
747
804
  <View
@@ -78,3 +78,15 @@ export const ProductActions = styled.View`
78
78
  export const ExtraOptionWrap = styled.ScrollView`
79
79
  margin-horizontal: -40px;
80
80
  `;
81
+
82
+ export const WeightUnitSwitch = styled.View`
83
+ margin-left: 10px;
84
+ `
85
+ export const WeightUnitItem = styled.View`
86
+ padding: 1px 5px;
87
+ border-radius: 4px;
88
+
89
+ ${({ active }: any) => active && css`
90
+ background-color: ${(props: any) => props.theme.colors.primary}20;
91
+ `}
92
+ `
@@ -10,18 +10,19 @@ const ProductIngredientUI = (props: any) => {
10
10
  const {
11
11
  state,
12
12
  ingredient,
13
- toggleSelect
13
+ toggleSelect,
14
+ isSoldOut
14
15
  } = props
15
16
 
16
17
  const theme = useTheme();
17
18
 
18
19
  return (
19
- <Container onPress={() => toggleSelect()}>
20
+ <Container disabled={isSoldOut} onPress={() => toggleSelect()}>
20
21
  <View>
21
- {state?.selected ? (
22
+ {state?.selected && !isSoldOut ? (
22
23
  <MaterialCommunityIcon name='checkbox-marked' color={theme.colors.primary} size={24} />
23
24
  ) : (
24
- <MaterialCommunityIcon name='checkbox-blank-outline' color={theme.colors.backgroundDark} size={24} />
25
+ <MaterialCommunityIcon name='checkbox-blank-outline' color='#cbcbcb' size={24} />
25
26
  )}
26
27
  </View>
27
28
  <OText mLeft={10}>
@@ -53,8 +53,8 @@ export const ProductOptionSubOptionUI = (props: any) => {
53
53
  const price = option?.with_half_option && suboption?.half_price && state.position !== 'whole' ? suboption?.half_price : suboption?.price
54
54
 
55
55
  return (
56
- <Container disabled={disabled}>
57
- <IconControl onPress={() => handleSuboptionClick()}>
56
+ <Container>
57
+ <IconControl disabled={disabled} onPress={() => handleSuboptionClick()}>
58
58
  {((option?.min === 0 && option?.max === 1) || option?.max > 1) ? (
59
59
  state?.selected ? (
60
60
  <OIcon src={theme.images.general.check_act} color={theme.colors.primary} width={16} />
@@ -73,30 +73,30 @@ export const ProductOptionSubOptionUI = (props: any) => {
73
73
  </OText>
74
74
  </IconControl>
75
75
  {showMessage && <OText size={10} mLeft={4} mRight={4} style={{ flex: 1, textAlign: 'center' }} color={theme.colors.primary}>{`${t('OPTIONS_MAX_LIMIT', 'Maximum options to choose')}: ${option?.max}`}</OText>}
76
- {option?.allow_suboption_quantity && (
76
+ {option?.allow_suboption_quantity && state?.selected && (
77
77
  <QuantityControl>
78
- <Checkbox disabled={state.quantity === 0} onPress={decrement}>
78
+ <Checkbox disabled={disabled || state.quantity === 0} onPress={decrement}>
79
79
  <OIcon
80
80
  src={theme.images.general.minus}
81
81
  width={16}
82
- color={state.quantity === 0 ? theme.colors.disabled : theme.colors.primary}
82
+ color={state.quantity === 0 || disabled ? theme.colors.disabled : theme.colors.primary}
83
83
  />
84
84
  </Checkbox>
85
85
  <OText mLeft={5} mRight={5}>
86
86
  {state.quantity}
87
87
  </OText>
88
- <Checkbox disabled={disableIncrement} onPress={increment}>
88
+ <Checkbox disabled={disabled || disableIncrement} onPress={increment}>
89
89
  <OIcon
90
90
  src={theme.images.general.plus}
91
91
  width={16}
92
- color={disableIncrement ? theme.colors.disabled : theme.colors.primary}
92
+ color={disableIncrement || disabled ? theme.colors.disabled : theme.colors.primary}
93
93
  />
94
94
  </Checkbox>
95
95
  </QuantityControl>
96
96
  )}
97
- {option?.with_half_option && (
97
+ {option?.with_half_option && state?.selected && (
98
98
  <PositionControl>
99
- <Circle onPress={() => changePosition('left')}>
99
+ <Circle disabled={disabled} onPress={() => changePosition('left')}>
100
100
  <OIcon
101
101
  src={theme.images.general.half_l}
102
102
  color={state.selected && state.position === 'left' ? theme.colors.primary : '#cbcbcb'}
@@ -104,14 +104,14 @@ export const ProductOptionSubOptionUI = (props: any) => {
104
104
  style={styles.inverse}
105
105
  />
106
106
  </Circle>
107
- <Circle onPress={() => changePosition('whole')}>
107
+ <Circle disabled={disabled} onPress={() => changePosition('whole')}>
108
108
  <OIcon
109
109
  src={theme.images.general.half_f}
110
110
  color={state.selected && state.position === 'whole' ? theme.colors.primary : '#cbcbcb'}
111
111
  width={16}
112
112
  />
113
113
  </Circle>
114
- <Circle onPress={() => changePosition('right')}>
114
+ <Circle disabled={disabled} onPress={() => changePosition('right')}>
115
115
  <OIcon
116
116
  src={theme.images.general.half_r}
117
117
  color={state.selected && state.position === 'right' ? theme.colors.primary : '#cbcbcb'}