ordering-ui-react-native 0.12.35 → 0.12.39

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 (54) hide show
  1. package/package.json +1 -1
  2. package/src/components/AddressForm/index.tsx +5 -5
  3. package/src/components/FacebookLogin/index.tsx +2 -2
  4. package/src/components/LoginForm/index.tsx +1 -1
  5. package/src/components/PaymentOptions/index.tsx +5 -5
  6. package/src/components/SignupForm/index.tsx +2 -2
  7. package/themes/business/src/components/AcceptOrRejectOrder/index.tsx +9 -8
  8. package/themes/business/src/components/LoginForm/index.tsx +1 -1
  9. package/themes/business/src/components/OrderDetails/Business.tsx +2 -4
  10. package/themes/business/src/components/OrderDetails/Delivery.tsx +111 -108
  11. package/themes/business/src/components/SearchBar/index.tsx +1 -1
  12. package/themes/business/src/components/SignupForm/index.tsx +2 -2
  13. package/themes/business/src/types/index.tsx +3 -3
  14. package/themes/doordash/src/components/AddressForm/index.tsx +5 -5
  15. package/themes/doordash/src/components/FacebookLogin/index.tsx +2 -2
  16. package/themes/doordash/src/components/LoginForm/index.tsx +1 -1
  17. package/themes/doordash/src/components/PaymentOptions/index.tsx +5 -5
  18. package/themes/doordash/src/components/SignupForm/index.tsx +2 -2
  19. package/themes/franchises/src/components/AddressForm/index.tsx +5 -5
  20. package/themes/franchises/src/components/FacebookLogin/index.tsx +2 -2
  21. package/themes/franchises/src/components/LoginForm/index.tsx +1 -1
  22. package/themes/franchises/src/components/PaymentOptions/index.tsx +3 -3
  23. package/themes/franchises/src/components/SignupForm/index.tsx +2 -2
  24. package/themes/instacart/src/components/AddressForm/index.tsx +5 -5
  25. package/themes/instacart/src/components/FacebookLogin/index.tsx +2 -2
  26. package/themes/instacart/src/components/LoginForm/index.tsx +1 -1
  27. package/themes/instacart/src/components/PaymentOptions/index.tsx +4 -4
  28. package/themes/instacart/src/components/SignupForm/index.tsx +2 -2
  29. package/themes/original/src/components/AddressForm/index.tsx +5 -5
  30. package/themes/original/src/components/FacebookLogin/index.tsx +2 -2
  31. package/themes/original/src/components/LoginForm/index.tsx +1 -1
  32. package/themes/original/src/components/PaymentOptions/index.tsx +5 -5
  33. package/themes/original/src/components/SignupForm/index.tsx +2 -2
  34. package/themes/single-business/src/components/AddressForm/index.tsx +5 -5
  35. package/themes/single-business/src/components/AppleLogin/index.tsx +2 -2
  36. package/themes/single-business/src/components/FacebookLogin/index.tsx +2 -2
  37. package/themes/single-business/src/components/GoogleLogin/index.tsx +2 -2
  38. package/themes/single-business/src/components/LanguageSelector/index.tsx +87 -70
  39. package/themes/single-business/src/components/LoginForm/index.tsx +1 -1
  40. package/themes/single-business/src/components/OrderDetails/index.tsx +14 -14
  41. package/themes/single-business/src/components/PaymentOptions/index.tsx +4 -4
  42. package/themes/single-business/src/components/ProductForm/index.tsx +682 -656
  43. package/themes/single-business/src/components/ProductForm/styles.tsx +1 -1
  44. package/themes/single-business/src/components/SignupForm/index.tsx +2 -2
  45. package/themes/single-business/src/components/UserProfile/index.tsx +2 -2
  46. package/themes/single-business/src/components/shared/OInput.tsx +1 -0
  47. package/themes/single-business/src/components/shared/OLink.tsx +80 -0
  48. package/themes/single-business/src/components/shared/index.tsx +2 -0
  49. package/themes/single-business/src/types/index.tsx +1 -0
  50. package/themes/uber-eats/src/components/AddressForm/index.tsx +5 -5
  51. package/themes/uber-eats/src/components/FacebookLogin/index.tsx +2 -2
  52. package/themes/uber-eats/src/components/LoginForm/index.tsx +1 -1
  53. package/themes/uber-eats/src/components/PaymentOptions/index.tsx +5 -5
  54. package/themes/uber-eats/src/components/SignupForm/index.tsx +2 -2
@@ -1,695 +1,721 @@
1
- import React from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import {
3
- ProductForm as ProductOptions,
4
- useSession,
5
- useLanguage,
6
- useOrder,
7
- useUtils,
3
+ ProductForm as ProductOptions,
4
+ useSession,
5
+ useLanguage,
6
+ useOrder,
7
+ useUtils,
8
8
  } from 'ordering-components/native';
9
9
  import { useTheme } from 'styled-components/native';
10
10
  import { ProductIngredient } from '../ProductIngredient';
11
11
  import { ProductOption } from '../ProductOption';
12
-
13
- import { View, TouchableOpacity, StyleSheet, Dimensions, Platform } from 'react-native';
12
+ import { View, TouchableOpacity, StyleSheet, Dimensions, Platform, useWindowDimensions, Keyboard } from 'react-native';
14
13
 
15
14
  import {
16
- ProductHeader,
17
- WrapHeader,
18
- TopHeader,
19
- WrapContent,
20
- ProductTitle,
21
- ProductDescription,
22
- ProductEditions,
23
- SectionTitle,
24
- WrapperIngredients,
25
- WrapperSubOption,
26
- ProductComment,
27
- ProductActions,
28
- ExtraOptionWrap,
15
+ ProductHeader,
16
+ WrapHeader,
17
+ TopHeader,
18
+ WrapContent,
19
+ ProductTitle,
20
+ ProductDescription,
21
+ ProductEditions,
22
+ SectionTitle,
23
+ WrapperIngredients,
24
+ WrapperSubOption,
25
+ ProductComment,
26
+ ProductActions,
27
+ ExtraOptionWrap,
29
28
  } from './styles';
30
29
  import { OButton, OIcon, OInput, OText } from '../shared';
31
30
  import { ScrollView } from 'react-native-gesture-handler';
32
31
  import { ProductOptionSubOption } from '../ProductOptionSubOption';
33
32
  import { NotFoundSource } from '../NotFoundSource';
34
33
  import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
35
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
34
+ import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
36
35
  import { useState } from 'react';
37
- import { useWindowDimensions } from 'react-native';
38
36
 
39
37
  const windowHeight = Dimensions.get('window').height;
40
38
  const windowWidth = Dimensions.get('window').width;
41
39
 
42
40
  export const ProductOptionsUI = (props: any) => {
43
- const {
44
- navigation,
45
- editMode,
46
- isSoldOut,
47
- productCart,
48
- increment,
49
- decrement,
50
- showOption,
51
- maxProductQuantity,
52
- errors,
53
- handleSave,
54
- handleChangeIngredientState,
55
- handleChangeSuboptionState,
56
- handleChangeCommentState,
57
- productObject,
58
- onClose,
59
- isFromCheckout,
60
- } = props;
41
+ const {
42
+ navigation,
43
+ editMode,
44
+ isSoldOut,
45
+ productCart,
46
+ increment,
47
+ decrement,
48
+ showOption,
49
+ maxProductQuantity,
50
+ errors,
51
+ handleSave,
52
+ handleChangeIngredientState,
53
+ handleChangeSuboptionState,
54
+ handleChangeCommentState,
55
+ productObject,
56
+ onClose,
57
+ isFromCheckout,
58
+ } = props;
59
+
60
+ const theme = useTheme();
61
+
62
+
63
+ const styles = StyleSheet.create({
64
+ mainContainer: {
61
65
 
62
- const theme = useTheme();
66
+ },
67
+ headerItem: {
68
+ overflow: 'hidden',
69
+ backgroundColor: theme.colors.clear,
70
+ width: 35,
71
+ marginVertical: 18,
72
+ },
73
+ optionContainer: {
74
+ marginBottom: 20,
75
+ },
76
+ comment: {
77
+ borderWidth: 1,
78
+ borderRadius: 7.6,
79
+ borderColor: theme.colors.border,
80
+ height: 100,
81
+ alignItems: 'flex-start',
82
+ },
83
+ quantityControl: {
84
+ flexDirection: 'row',
85
+ justifyContent: 'space-between',
86
+ alignItems: 'center',
87
+ marginRight: 10,
88
+ },
89
+ btnBackArrow: {
90
+ borderWidth: 0,
91
+ backgroundColor: 'rgba(0,0,0,0.3)',
92
+ borderRadius: 24,
93
+ marginRight: 15,
94
+ },
95
+ productHeaderSkeleton: {
96
+ flexDirection: 'row',
97
+ width: '100%',
98
+ position: 'relative',
99
+ maxHeight: 260,
100
+ height: 260,
101
+ resizeMode: 'cover',
102
+ minHeight: 200,
103
+ zIndex: 0,
104
+ },
105
+ extraItem: {
106
+ paddingHorizontal: 7,
107
+ paddingBottom: 10,
108
+ borderBottomWidth: 1,
109
+ borderBottomColor: theme.colors.border,
110
+ justifyContent: 'center',
111
+ },
112
+ });
63
113
 
114
+ const [{ parsePrice }] = useUtils();
115
+ const [, t] = useLanguage();
116
+ const [orderState] = useOrder();
117
+ const [{ auth }] = useSession();
118
+ const { product, loading, error } = productObject;
64
119
 
65
- const styles = StyleSheet.create({
66
- mainContainer: {
120
+ const { top, bottom } = useSafeAreaInsets();
121
+ const { height } = useWindowDimensions();
122
+ const [selOpt, setSelectedOpt] = useState(0);
67
123
 
68
- },
69
- headerItem: {
70
- overflow: 'hidden',
71
- backgroundColor: theme.colors.clear,
72
- width: 35,
73
- marginVertical: 18,
74
- },
75
- optionContainer: {
76
- marginBottom: 20,
77
- },
78
- comment: {
79
- borderWidth: 1,
80
- borderRadius: 7.6,
81
- borderColor: theme.colors.border,
82
- height: 100,
83
- alignItems: 'flex-start',
84
- },
85
- quantityControl: {
86
- flexDirection: 'row',
87
- justifyContent: 'space-between',
88
- alignItems: 'center',
89
- marginRight: 10,
90
- },
91
- btnBackArrow: {
92
- borderWidth: 0,
93
- backgroundColor: 'rgba(0,0,0,0.3)',
94
- borderRadius: 24,
95
- marginRight: 15,
96
- },
97
- productHeaderSkeleton: {
98
- flexDirection: 'row',
99
- width: '100%',
100
- position: 'relative',
101
- maxHeight: 260,
102
- height: 260,
103
- resizeMode: 'cover',
104
- minHeight: 200,
105
- zIndex: 0,
106
- },
107
- extraItem: {
108
- paddingHorizontal: 7,
109
- paddingBottom: 10,
110
- borderBottomWidth: 1,
111
- borderBottomColor: theme.colors.border,
112
- justifyContent: 'center',
113
- },
114
- });
124
+ const isError = (id: number) => {
125
+ let bgColor = theme.colors.white;
126
+ if (errors[`id:${id}`]) {
127
+ bgColor = 'rgba(255, 0, 0, 0.05)';
128
+ }
129
+ if (isSoldOut || maxProductQuantity <= 0) {
130
+ bgColor = 'hsl(0, 0%, 72%)';
131
+ }
132
+ return bgColor;
133
+ };
115
134
 
116
- const [{ parsePrice }] = useUtils();
117
- const [, t] = useLanguage();
118
- const [orderState] = useOrder();
119
- const [{ auth }] = useSession();
120
- const { product, loading, error } = productObject;
135
+ const handleSaveProduct = () => {
136
+ console.log('----- click handle ------')
137
+ const isErrors = Object.values(errors).length > 0;
138
+ if (!isErrors) {
139
+ console.log('----- save handle ------')
140
+ handleSave && handleSave();
141
+ return;
142
+ }
143
+ };
121
144
 
122
- const { top, bottom } = useSafeAreaInsets();
123
- const { height } = useWindowDimensions();
124
- const [selOpt, setSelectedOpt] = useState(0);
145
+ const hasRespected = (options: Array<any>, respect_id: number) => {
146
+ if (respect_id == null) return;
147
+ const option: any = options.filter(({ id }: any) => id === selOpt);
148
+ if (option == undefined) return false;
149
+ if (option?.suboptions?.length == 0) return false;
150
+ const sel = option[0]?.suboptions?.filter(
151
+ ({ id }: any) => id === respect_id,
152
+ );
153
+ return sel[0]?.id !== undefined;
154
+ };
125
155
 
126
- const isError = (id: number) => {
127
- let bgColor = theme.colors.white;
128
- if (errors[`id:${id}`]) {
129
- bgColor = 'rgba(255, 0, 0, 0.05)';
130
- }
131
- if (isSoldOut || maxProductQuantity <= 0) {
132
- bgColor = 'hsl(0, 0%, 72%)';
133
- }
134
- return bgColor;
135
- };
156
+ const handleRedirectLogin = () => {
157
+ onClose();
158
+ navigation.navigate('Login');
159
+ };
136
160
 
137
- const handleSaveProduct = () => {
138
- console.log('----- click handle ------')
139
- const isErrors = Object.values(errors).length > 0;
140
- if (!isErrors) {
141
- console.log('----- save handle ------')
142
- handleSave && handleSave();
143
- return;
144
- }
145
- };
161
+ const saveErrors =
162
+ orderState.loading ||
163
+ maxProductQuantity === 0 ||
164
+ Object.keys(errors).length > 0;
146
165
 
147
- const hasRespected = (options: Array<any>, respect_id: number) => {
148
- if (respect_id == null) return;
149
- const option: any = options.filter(({ id }: any) => id === selOpt);
150
- if (option == undefined) return false;
151
- if (option?.suboptions?.length == 0) return false;
152
- const sel = option[0]?.suboptions?.filter(
153
- ({ id }: any) => id === respect_id,
154
- );
155
- return sel[0]?.id !== undefined;
156
- };
166
+ const ExtraOptions = ({ eID, options }: any) => (
167
+ <ExtraOptionWrap
168
+ horizontal
169
+ showsHorizontalScrollIndicator={false}
170
+ style={{ marginBottom: 20 }}
171
+ contentContainerStyle={{ paddingHorizontal: 33 }}>
172
+ <>
173
+ <TouchableOpacity
174
+ key={`eopt_all_0`}
175
+ onPress={() => setSelectedOpt(0)}
176
+ style={[
177
+ styles.extraItem,
178
+ {
179
+ borderBottomColor:
180
+ selOpt == 0 ? theme.colors.textNormal : theme.colors.border,
181
+ },
182
+ ]}>
183
+ <OText
184
+ color={selOpt == 0 ? theme.colors.textNormal : theme.colors.textSecondary}
185
+ size={selOpt == 0 ? 14 : 12}
186
+ weight={selOpt == 0 ? '600' : 'normal'}>
187
+ {t('ALL', 'All')}
188
+ </OText>
189
+ </TouchableOpacity>
190
+ {product?.ingredients.length > 0 && (
191
+ <TouchableOpacity
192
+ key={`eopt_all_00`}
193
+ onPress={() => setSelectedOpt(-1)}
194
+ style={[
195
+ styles.extraItem,
196
+ {
197
+ borderBottomColor:
198
+ selOpt == -1 ? theme.colors.textNormal : theme.colors.border,
199
+ },
200
+ ]}>
201
+ <OText
202
+ color={selOpt == -1 ? theme.colors.textNormal : theme.colors.textSecondary}
203
+ size={selOpt == -1 ? 14 : 12}
204
+ weight={selOpt == -1 ? '600' : 'normal'}>
205
+ {t('INGREDIENTS', 'Ingredients')}
206
+ </OText>
207
+ </TouchableOpacity>
208
+ )}
209
+ {options.map(({ id, name, respect_to }: any) => (
210
+ <React.Fragment key={`cont_key_${id}`}>
211
+ {respect_to == null && (
212
+ <TouchableOpacity
213
+ key={`eopt_key_${id}`}
214
+ onPress={() => setSelectedOpt(id)}
215
+ style={[
216
+ styles.extraItem,
217
+ {
218
+ borderBottomColor:
219
+ selOpt == id ? theme.colors.textNormal : theme.colors.border,
220
+ },
221
+ ]}>
222
+ <OText
223
+ color={
224
+ selOpt == id ? theme.colors.textNormal : theme.colors.textSecondary
225
+ }
226
+ size={selOpt == id ? 14 : 12}
227
+ weight={selOpt == id ? '600' : 'normal'}>
228
+ {name}
229
+ </OText>
230
+ </TouchableOpacity>
231
+ )}
232
+ </React.Fragment>
233
+ ))}
234
+ </>
235
+ </ExtraOptionWrap>
236
+ );
157
237
 
158
- const handleRedirectLogin = () => {
159
- onClose();
160
- navigation.navigate('Login');
161
- };
238
+ const [isKeyboardShow, setIsKeyboardShow] = useState(false)
162
239
 
163
- const saveErrors =
164
- orderState.loading ||
165
- maxProductQuantity === 0 ||
166
- Object.keys(errors).length > 0;
240
+ useEffect(() => {
241
+ const keyboardDidShowListener = Keyboard.addListener(
242
+ 'keyboardDidShow',
243
+ () => {
244
+ setIsKeyboardShow(true);
245
+ }
246
+ );
247
+ const keyboardDidHideListener = Keyboard.addListener(
248
+ 'keyboardDidHide',
249
+ () => {
250
+ setIsKeyboardShow(false);
251
+ }
252
+ );
167
253
 
168
- const ExtraOptions = ({ eID, options }: any) => (
169
- <ExtraOptionWrap
170
- horizontal
171
- showsHorizontalScrollIndicator={false}
172
- style={{ marginBottom: 20 }}
173
- contentContainerStyle={{ paddingHorizontal: 33 }}>
174
- <>
175
- <TouchableOpacity
176
- key={`eopt_all_0`}
177
- onPress={() => setSelectedOpt(0)}
178
- style={[
179
- styles.extraItem,
180
- {
181
- borderBottomColor:
182
- selOpt == 0 ? theme.colors.textNormal : theme.colors.border,
183
- },
184
- ]}>
185
- <OText
186
- color={selOpt == 0 ? theme.colors.textNormal : theme.colors.textSecondary}
187
- size={selOpt == 0 ? 14 : 12}
188
- weight={selOpt == 0 ? '600' : 'normal'}>
189
- {t('ALL', 'All')}
190
- </OText>
191
- </TouchableOpacity>
192
- {product?.ingredients.length > 0 && (
193
- <TouchableOpacity
194
- key={`eopt_all_00`}
195
- onPress={() => setSelectedOpt(-1)}
196
- style={[
197
- styles.extraItem,
198
- {
199
- borderBottomColor:
200
- selOpt == -1 ? theme.colors.textNormal : theme.colors.border,
201
- },
202
- ]}>
203
- <OText
204
- color={selOpt == -1 ? theme.colors.textNormal : theme.colors.textSecondary}
205
- size={selOpt == -1 ? 14 : 12}
206
- weight={selOpt == -1 ? '600' : 'normal'}>
207
- {t('INGREDIENTS', 'Ingredients')}
208
- </OText>
209
- </TouchableOpacity>
210
- )}
211
- {options.map(({ id, name, respect_to }: any) => (
212
- <React.Fragment key={`cont_key_${id}`}>
213
- {respect_to == null && (
214
- <TouchableOpacity
215
- key={`eopt_key_${id}`}
216
- onPress={() => setSelectedOpt(id)}
217
- style={[
218
- styles.extraItem,
219
- {
220
- borderBottomColor:
221
- selOpt == id ? theme.colors.textNormal : theme.colors.border,
222
- },
223
- ]}>
224
- <OText
225
- color={
226
- selOpt == id ? theme.colors.textNormal : theme.colors.textSecondary
227
- }
228
- size={selOpt == id ? 14 : 12}
229
- weight={selOpt == id ? '600' : 'normal'}>
230
- {name}
231
- </OText>
232
- </TouchableOpacity>
233
- )}
234
- </React.Fragment>
235
- ))}
236
- </>
237
- </ExtraOptionWrap>
238
- );
254
+ return () => {
255
+ keyboardDidHideListener.remove();
256
+ keyboardDidShowListener.remove();
257
+ };
258
+ }, []);
239
259
 
240
- return (
241
- <View style={{ height: height }}>
242
- <View style={{ height: height - top - bottom - (Platform.OS === 'android' ? 94 : 69) }}>
243
- <ScrollView>
244
- {!error && (
245
- <>
246
- <WrapHeader>
247
- {loading && !product ? (
248
- <View style={styles.productHeaderSkeleton}>
249
- <Placeholder Animation={Fade}>
250
- <PlaceholderLine
251
- height={258}
252
- style={{ borderRadius: 0 }}
253
- width={windowWidth}
254
- />
255
- </Placeholder>
256
- </View>
257
- ) : (
258
- <>
259
- <TopHeader>
260
- <TouchableOpacity
261
- style={styles.headerItem}
262
- onPress={onClose}>
263
- <OIcon src={theme.images.general.close} width={16} />
264
- </TouchableOpacity>
265
- </TopHeader>
266
- <ProductHeader
267
- source={{ uri: product?.images || productCart?.images }}
268
- resizeMode={'contain'}
269
- />
270
- </>
271
- )}
272
- </WrapHeader>
273
- <WrapContent>
274
- <ProductTitle>
275
- {loading && !product ? (
276
- <Placeholder Animation={Fade}>
277
- <View
278
- style={{
279
- flexDirection: 'row',
280
- justifyContent: 'space-between',
281
- }}>
282
- <PlaceholderLine width={40} height={20} />
283
- <PlaceholderLine width={30} height={20} />
284
- </View>
285
- </Placeholder>
286
- ) : (
287
- <>
288
- <OText
289
- size={20}
290
- lineHeight={30}
291
- weight={'600'}
292
- style={{ flex: 1, marginBottom: 5 }}>
293
- {product?.name || productCart.name}
294
- </OText>
295
- <OText size={16} lineHeight={24} color={theme.colors.textNormal}>
296
- {productCart.price ? parsePrice(productCart.price) : ''}
297
- </OText>
298
- </>
299
- )}
300
- </ProductTitle>
301
- <ProductDescription>
302
- <OText color={theme.colors.textSecondary} size={12} lineHeight={18}>
303
- {product?.description || productCart?.description}
304
- </OText>
305
- {((product?.sku &&
306
- product?.sku !== '-1' &&
307
- product?.sku !== '1') ||
308
- (productCart?.sku &&
309
- productCart?.sku !== '-1' &&
310
- productCart?.sku !== '1')) && (
311
- <>
312
- <OText size={16}>{t('SKU', 'Sku')}</OText>
313
- <OText>{product?.sku || productCart?.sku}</OText>
314
- </>
315
- )}
316
- </ProductDescription>
317
- {loading && !product ? (
318
- <>
319
- {[...Array(2)].map((item, i) => (
320
- <Placeholder
321
- key={i}
322
- style={{ marginBottom: 20 }}
323
- Animation={Fade}>
324
- <PlaceholderLine
325
- height={40}
326
- style={{ flex: 1, marginTop: 10 }}
327
- />
328
- {[...Array(3)].map((item, i) => (
329
- <View
330
- key={'place_key_' + i}
331
- style={{
332
- flexDirection: 'row',
333
- justifyContent: 'space-between',
334
- }}>
335
- <PlaceholderLine
336
- height={30}
337
- width={10}
338
- style={{ marginBottom: 20 }}
339
- />
340
- <PlaceholderLine
341
- height={30}
342
- width={50}
343
- style={{ marginBottom: 20 }}
344
- />
345
- <PlaceholderLine
346
- height={30}
347
- width={30}
348
- style={{ marginBottom: 20 }}
349
- />
350
- </View>
351
- ))}
352
- </Placeholder>
353
- ))}
354
- </>
355
- ) : (
356
- <ProductEditions>
357
- {product?.extras.map((extra: any) =>
358
- <ExtraOptions key={extra.id} options={extra.options} />
359
- )}
260
+ return (
261
+ <>
262
+ <ScrollView style={{ height: windowHeight * 0.85 }}>
263
+ {!error && (
264
+ <>
265
+ <WrapHeader>
266
+ {loading && !product ? (
267
+ <View style={styles.productHeaderSkeleton}>
268
+ <Placeholder Animation={Fade}>
269
+ <PlaceholderLine
270
+ height={258}
271
+ style={{ borderRadius: 0 }}
272
+ width={windowWidth}
273
+ />
274
+ </Placeholder>
275
+ </View>
276
+ ) : (
277
+ <>
278
+ <TopHeader>
279
+ <TouchableOpacity
280
+ style={styles.headerItem}
281
+ onPress={onClose}>
282
+ <OIcon src={theme.images.general.close} width={16} />
283
+ </TouchableOpacity>
284
+ </TopHeader>
285
+ <ProductHeader
286
+ source={{ uri: product?.images || productCart?.images }}
287
+ resizeMode={'contain'}
288
+ />
289
+ </>
290
+ )}
291
+ </WrapHeader>
292
+ <WrapContent>
293
+ <ProductTitle>
294
+ {loading && !product ? (
295
+ <Placeholder Animation={Fade}>
296
+ <View
297
+ style={{
298
+ flexDirection: 'row',
299
+ justifyContent: 'space-between',
300
+ }}>
301
+ <PlaceholderLine width={40} height={20} />
302
+ <PlaceholderLine width={30} height={20} />
303
+ </View>
304
+ </Placeholder>
305
+ ) : (
306
+ <>
307
+ <OText
308
+ size={20}
309
+ lineHeight={30}
310
+ weight={'600'}
311
+ style={{ flex: 1, marginBottom: 5 }}>
312
+ {product?.name || productCart.name}
313
+ </OText>
314
+ <OText size={16} lineHeight={24} color={theme.colors.textNormal}>
315
+ {productCart.price ? parsePrice(productCart.price) : ''}
316
+ </OText>
317
+ </>
318
+ )}
319
+ </ProductTitle>
320
+ <ProductDescription>
321
+ <OText color={theme.colors.textSecondary} size={12} lineHeight={18}>
322
+ {product?.description || productCart?.description}
323
+ </OText>
324
+ {((product?.sku &&
325
+ product?.sku !== '-1' &&
326
+ product?.sku !== '1') ||
327
+ (productCart?.sku &&
328
+ productCart?.sku !== '-1' &&
329
+ productCart?.sku !== '1')) && (
330
+ <>
331
+ <OText size={16}>{t('SKU', 'Sku')}</OText>
332
+ <OText>{product?.sku || productCart?.sku}</OText>
333
+ </>
334
+ )}
335
+ </ProductDescription>
336
+ {loading && !product ? (
337
+ <>
338
+ {[...Array(2)].map((item, i) => (
339
+ <Placeholder
340
+ key={i}
341
+ style={{ marginBottom: 20 }}
342
+ Animation={Fade}>
343
+ <PlaceholderLine
344
+ height={40}
345
+ style={{ flex: 1, marginTop: 10 }}
346
+ />
347
+ {[...Array(3)].map((item, i) => (
348
+ <View
349
+ key={'place_key_' + i}
350
+ style={{
351
+ flexDirection: 'row',
352
+ justifyContent: 'space-between',
353
+ }}>
354
+ <PlaceholderLine
355
+ height={30}
356
+ width={10}
357
+ style={{ marginBottom: 20 }}
358
+ />
359
+ <PlaceholderLine
360
+ height={30}
361
+ width={50}
362
+ style={{ marginBottom: 20 }}
363
+ />
364
+ <PlaceholderLine
365
+ height={30}
366
+ width={30}
367
+ style={{ marginBottom: 20 }}
368
+ />
369
+ </View>
370
+ ))}
371
+ </Placeholder>
372
+ ))}
373
+ </>
374
+ ) : (
375
+ <ProductEditions>
376
+ {product?.extras.map((extra: any) =>
377
+ <ExtraOptions key={extra.id} options={extra.options} />
378
+ )}
360
379
 
361
- {selOpt == 0 ? (
362
- <>
363
- {product?.ingredients.length > 0 && (
364
- <View style={styles.optionContainer}>
365
- <SectionTitle>
366
- <OText size={16}>
367
- {t('INGREDIENTS', 'Ingredients')}
368
- </OText>
369
- </SectionTitle>
370
- <WrapperIngredients
371
- style={{
372
- backgroundColor:
373
- isSoldOut || maxProductQuantity <= 0
374
- ? 'hsl(0, 0%, 72%)'
375
- : theme.colors.white,
376
- }}>
377
- {product?.ingredients.map((ingredient: any) => (
378
- <ProductIngredient
379
- key={ingredient.id}
380
- ingredient={ingredient}
381
- state={
382
- productCart.ingredients[`id:${ingredient.id}`]
383
- }
384
- onChange={handleChangeIngredientState}
385
- />
386
- ))}
387
- </WrapperIngredients>
388
- </View>
389
- )}
390
- {product?.extras.map((extra: any) =>
391
- extra.options.map((option: any) => {
392
- const currentState =
393
- productCart.options[`id:${option.id}`] || {};
394
- return (
395
- <React.Fragment key={`popt_${option.id}`}>
396
- {showOption(option) && (
397
- <View style={styles.optionContainer}>
398
- <ProductOption
399
- option={option}
400
- currentState={currentState}
401
- error={errors[`id:${option.id}`]}>
402
- <WrapperSubOption
403
- style={{
404
- backgroundColor: isError(option.id),
405
- }}>
406
- {option.suboptions.map(
407
- (suboption: any) => {
408
- const currentState =
409
- productCart.options[
410
- `id:${option.id}`
411
- ]?.suboptions[
412
- `id:${suboption.id}`
413
- ] || {};
414
- const balance =
415
- productCart.options[
416
- `id:${option.id}`
417
- ]?.balance || 0;
418
- return (
419
- <ProductOptionSubOption
420
- key={suboption.id}
421
- onChange={
422
- handleChangeSuboptionState
423
- }
424
- balance={balance}
425
- option={option}
426
- suboption={suboption}
427
- state={currentState}
428
- disabled={
429
- isSoldOut ||
430
- maxProductQuantity <= 0
431
- }
432
- />
433
- );
434
- },
435
- )}
436
- </WrapperSubOption>
437
- </ProductOption>
438
- </View>
439
- )}
440
- </React.Fragment>
441
- );
442
- }),
443
- )}
444
- </>
445
- ) : (
446
- <>
447
- {selOpt == -1 ? (
448
- <View style={styles.optionContainer}>
449
- <SectionTitle>
450
- <OText size={16}>
451
- {t('INGREDIENTS', 'Ingredients')}
452
- </OText>
453
- </SectionTitle>
454
- <WrapperIngredients
455
- style={{
456
- backgroundColor:
457
- isSoldOut || maxProductQuantity <= 0
458
- ? 'hsl(0, 0%, 72%)'
459
- : theme.colors.white,
460
- }}>
461
- {product?.ingredients.map((ingredient: any) => (
462
- <ProductIngredient
463
- key={ingredient.id}
464
- ingredient={ingredient}
465
- state={
466
- productCart.ingredients[`id:${ingredient.id}`]
467
- }
468
- onChange={handleChangeIngredientState}
469
- />
470
- ))}
471
- </WrapperIngredients>
472
- </View>
473
- ) : (
474
- <>
475
- {product?.extras.map((extra: any) =>
476
- extra.options.map((option: any) => {
477
- if (
478
- option.id == selOpt ||
479
- (hasRespected(
480
- extra.options,
481
- option.respect_to,
482
- ) &&
483
- showOption(option))
484
- ) {
485
- const currentState =
486
- productCart.options[`id:${option.id}`] || {};
487
- return (
488
- <React.Fragment key={option.id}>
489
- {showOption(option) && (
490
- <View style={styles.optionContainer}>
491
- <ProductOption
492
- option={option}
493
- currentState={currentState}
494
- error={errors[`id:${option.id}`]}>
495
- <WrapperSubOption
496
- style={{
497
- backgroundColor: isError(
498
- option.id,
499
- ),
500
- }}>
501
- {option.suboptions.map(
502
- (suboption: any) => {
503
- const currentState =
504
- productCart.options[
505
- `id:${option.id}`
506
- ]?.suboptions[
507
- `id:${suboption.id}`
508
- ] || {};
509
- const balance =
510
- productCart.options[
511
- `id:${option.id}`
512
- ]?.balance || 0;
513
- return (
514
- <ProductOptionSubOption
515
- key={suboption.id}
516
- onChange={
517
- handleChangeSuboptionState
518
- }
519
- balance={balance}
520
- option={option}
521
- suboption={suboption}
522
- state={currentState}
523
- disabled={
524
- isSoldOut ||
525
- maxProductQuantity <= 0
526
- }
527
- />
528
- );
529
- },
530
- )}
531
- </WrapperSubOption>
532
- </ProductOption>
533
- </View>
534
- )}
535
- </React.Fragment>
536
- );
537
- }
538
- }),
539
- )}
540
- </>
541
- )}
542
- </>
543
- )}
544
- <ProductComment>
545
- <SectionTitle>
546
- <OText size={16} weight={'600'} lineHeight={24}>
547
- {t('SPECIAL_COMMENT', 'Special comment')}
548
- </OText>
549
- </SectionTitle>
550
- <OInput
551
- multiline
552
- placeholder={t('SPECIAL_COMMENT', 'Special comment')}
553
- value={productCart.comment}
554
- onChange={(val: string) =>
555
- handleChangeCommentState({ target: { value: val } })
556
- }
557
- isDisabled={
558
- !(productCart && !isSoldOut && maxProductQuantity)
559
- }
560
- style={styles.comment}
561
- />
562
- </ProductComment>
563
- </ProductEditions>
564
- )}
565
- </WrapContent>
566
- </>
567
- )}
568
- {error && error.length > 0 && (
569
- <NotFoundSource content={error[0]?.message || error[0]} />
570
- )}
571
- </ScrollView>
572
- </View>
573
- {!loading && !error && product && (
574
- <ProductActions style={{ paddingBottom: bottom + 12 }}>
575
- <OText size={16} lineHeight={24} weight={'600'}>
576
- {productCart.total ? parsePrice(productCart?.total) : ''}
577
- </OText>
578
- {productCart && !isSoldOut && maxProductQuantity > 0 && (
579
- <View style={styles.quantityControl}>
580
- <TouchableOpacity
581
- onPress={decrement}
582
- disabled={productCart.quantity === 1 || isSoldOut}>
583
- <OIcon
584
- src={theme.images.general.minus}
585
- width={16}
586
- color={
587
- productCart.quantity === 1 || isSoldOut
588
- ? theme.colors.backgroundGray
589
- : theme.colors.backgroundDark
590
- }
591
- />
592
- </TouchableOpacity>
593
- <OText
594
- size={12}
595
- lineHeight={18}
596
- style={{ minWidth: 29, textAlign: 'center' }}>
597
- {productCart.quantity}
598
- </OText>
599
- <TouchableOpacity
600
- onPress={increment}
601
- disabled={
602
- maxProductQuantity <= 0 ||
603
- productCart.quantity >= maxProductQuantity ||
604
- isSoldOut
605
- }>
606
- <OIcon
607
- src={theme.images.general.plus}
608
- width={16}
609
- color={
610
- maxProductQuantity <= 0 ||
611
- productCart.quantity >= maxProductQuantity ||
612
- isSoldOut
613
- ? theme.colors.backgroundGray
614
- : theme.colors.backgroundDark
615
- }
616
- />
617
- </TouchableOpacity>
618
- </View>
619
- )}
620
- <View
621
- style={{
622
- width: isSoldOut || maxProductQuantity <= 0 ? '100%' : '40%',
623
- }}>
624
- {productCart &&
625
- !isSoldOut &&
626
- maxProductQuantity > 0 &&
627
- auth &&
628
- orderState.options?.address_id && (
629
- <OButton
630
- onClick={() => handleSaveProduct()}
631
- imgRightSrc=""
632
- text={`${orderState.loading
633
- ? t('LOADING', 'Loading')
634
- : editMode
635
- ? t('UPDATE', 'Update')
636
- : t('ADD', 'Add')
637
- }`}
638
- textStyle={{
639
- color: saveErrors ? theme.colors.primary : theme.colors.white,
640
- }}
641
- style={{
642
- backgroundColor: saveErrors ? theme.colors.white : theme.colors.primary,
643
- borderColor: saveErrors ? theme.colors.white : theme.colors.primary,
644
- opacity: saveErrors ? 0.3 : 1,
645
- borderRadius: 7.6,
646
- height: 44,
647
- shadowOpacity: 0,
648
- borderWidth: 1,
649
- }}
650
- />
651
- )}
652
- {auth &&
653
- !orderState.options?.address_id &&
654
- (orderState.loading ? (
655
- <OButton
656
- isDisabled
657
- text={t('LOADING', 'Loading')}
658
- imgRightSrc=""
659
- />
660
- ) : (
661
- <OButton onClick={navigation.navigate('AddressList')} />
662
- ))}
663
- {(!auth || isSoldOut || maxProductQuantity <= 0) && (
664
- <OButton
665
- isDisabled={isSoldOut || maxProductQuantity <= 0}
666
- onClick={() => handleRedirectLogin()}
667
- text={
668
- isSoldOut || maxProductQuantity <= 0
669
- ? t('SOLD_OUT', 'Sold out')
670
- : t('LOGIN_SIGNUP', 'Login / Sign Up')
671
- }
672
- imgRightSrc=""
673
- textStyle={{ color: theme.colors.primary }}
674
- style={{
675
- borderColor: theme.colors.primary,
676
- backgroundColor: theme.colors.white,
677
- }}
678
- />
679
- )}
680
- </View>
681
- </ProductActions>
682
- )}
683
- </View>
684
- );
380
+ {selOpt == 0 ? (
381
+ <>
382
+ {product?.ingredients.length > 0 && (
383
+ <View style={styles.optionContainer}>
384
+ <SectionTitle>
385
+ <OText size={16}>
386
+ {t('INGREDIENTS', 'Ingredients')}
387
+ </OText>
388
+ </SectionTitle>
389
+ <WrapperIngredients
390
+ style={{
391
+ backgroundColor:
392
+ isSoldOut || maxProductQuantity <= 0
393
+ ? 'hsl(0, 0%, 72%)'
394
+ : theme.colors.white,
395
+ }}>
396
+ {product?.ingredients.map((ingredient: any) => (
397
+ <ProductIngredient
398
+ key={ingredient.id}
399
+ ingredient={ingredient}
400
+ state={
401
+ productCart.ingredients[`id:${ingredient.id}`]
402
+ }
403
+ onChange={handleChangeIngredientState}
404
+ />
405
+ ))}
406
+ </WrapperIngredients>
407
+ </View>
408
+ )}
409
+ {product?.extras.map((extra: any) =>
410
+ extra.options.map((option: any) => {
411
+ const currentState =
412
+ productCart.options[`id:${option.id}`] || {};
413
+ return (
414
+ <React.Fragment key={`popt_${option.id}`}>
415
+ {showOption(option) && (
416
+ <View style={styles.optionContainer}>
417
+ <ProductOption
418
+ option={option}
419
+ currentState={currentState}
420
+ error={errors[`id:${option.id}`]}>
421
+ <WrapperSubOption
422
+ style={{
423
+ backgroundColor: isError(option.id),
424
+ }}>
425
+ {option.suboptions.map(
426
+ (suboption: any) => {
427
+ const currentState =
428
+ productCart.options[
429
+ `id:${option.id}`
430
+ ]?.suboptions[
431
+ `id:${suboption.id}`
432
+ ] || {};
433
+ const balance =
434
+ productCart.options[
435
+ `id:${option.id}`
436
+ ]?.balance || 0;
437
+ return (
438
+ <ProductOptionSubOption
439
+ key={suboption.id}
440
+ onChange={
441
+ handleChangeSuboptionState
442
+ }
443
+ balance={balance}
444
+ option={option}
445
+ suboption={suboption}
446
+ state={currentState}
447
+ disabled={
448
+ isSoldOut ||
449
+ maxProductQuantity <= 0
450
+ }
451
+ />
452
+ );
453
+ },
454
+ )}
455
+ </WrapperSubOption>
456
+ </ProductOption>
457
+ </View>
458
+ )}
459
+ </React.Fragment>
460
+ );
461
+ }),
462
+ )}
463
+ </>
464
+ ) : (
465
+ <>
466
+ {selOpt == -1 ? (
467
+ <View style={styles.optionContainer}>
468
+ <SectionTitle>
469
+ <OText size={16}>
470
+ {t('INGREDIENTS', 'Ingredients')}
471
+ </OText>
472
+ </SectionTitle>
473
+ <WrapperIngredients
474
+ style={{
475
+ backgroundColor:
476
+ isSoldOut || maxProductQuantity <= 0
477
+ ? 'hsl(0, 0%, 72%)'
478
+ : theme.colors.white,
479
+ }}>
480
+ {product?.ingredients.map((ingredient: any) => (
481
+ <ProductIngredient
482
+ key={ingredient.id}
483
+ ingredient={ingredient}
484
+ state={
485
+ productCart.ingredients[`id:${ingredient.id}`]
486
+ }
487
+ onChange={handleChangeIngredientState}
488
+ />
489
+ ))}
490
+ </WrapperIngredients>
491
+ </View>
492
+ ) : (
493
+ <>
494
+ {product?.extras.map((extra: any) =>
495
+ extra.options.map((option: any) => {
496
+ if (
497
+ option.id == selOpt ||
498
+ (hasRespected(
499
+ extra.options,
500
+ option.respect_to,
501
+ ) &&
502
+ showOption(option))
503
+ ) {
504
+ const currentState =
505
+ productCart.options[`id:${option.id}`] || {};
506
+ return (
507
+ <React.Fragment key={option.id}>
508
+ {showOption(option) && (
509
+ <View style={styles.optionContainer}>
510
+ <ProductOption
511
+ option={option}
512
+ currentState={currentState}
513
+ error={errors[`id:${option.id}`]}>
514
+ <WrapperSubOption
515
+ style={{
516
+ backgroundColor: isError(
517
+ option.id,
518
+ ),
519
+ }}>
520
+ {option.suboptions.map(
521
+ (suboption: any) => {
522
+ const currentState =
523
+ productCart.options[
524
+ `id:${option.id}`
525
+ ]?.suboptions[
526
+ `id:${suboption.id}`
527
+ ] || {};
528
+ const balance =
529
+ productCart.options[
530
+ `id:${option.id}`
531
+ ]?.balance || 0;
532
+ return (
533
+ <ProductOptionSubOption
534
+ key={suboption.id}
535
+ onChange={
536
+ handleChangeSuboptionState
537
+ }
538
+ balance={balance}
539
+ option={option}
540
+ suboption={suboption}
541
+ state={currentState}
542
+ disabled={
543
+ isSoldOut ||
544
+ maxProductQuantity <= 0
545
+ }
546
+ />
547
+ );
548
+ },
549
+ )}
550
+ </WrapperSubOption>
551
+ </ProductOption>
552
+ </View>
553
+ )}
554
+ </React.Fragment>
555
+ );
556
+ }
557
+ }),
558
+ )}
559
+ </>
560
+ )}
561
+ </>
562
+ )}
563
+ <ProductComment style={{ paddingBottom: isKeyboardShow ? 200 : 0 }}>
564
+ <SectionTitle>
565
+ <OText size={16} weight={'600'} lineHeight={24}>
566
+ {t('SPECIAL_COMMENT', 'Special comment')}
567
+ </OText>
568
+ </SectionTitle>
569
+ <OInput
570
+ multiline={true}
571
+ numberOfLines={10}
572
+ placeholder={t('SPECIAL_COMMENT', 'Special comment')}
573
+ value={productCart.comment}
574
+ onChange={(val: string) =>
575
+ handleChangeCommentState({ target: { value: val } })
576
+ }
577
+ isDisabled={
578
+ !(productCart && !isSoldOut && maxProductQuantity)
579
+ }
580
+ style={{
581
+ height: 100,
582
+ justifyContent: "flex-end",
583
+ alignItems: 'flex-start',
584
+ borderWidth: 1,
585
+ borderRadius: 8,
586
+ borderColor: theme.colors.border,
587
+ }}
588
+ />
589
+ </ProductComment>
590
+ </ProductEditions>
591
+ )}
592
+ </WrapContent>
593
+ </>
594
+ )}
595
+ {error && error.length > 0 && (
596
+ <NotFoundSource content={error[0]?.message || error[0]} />
597
+ )}
598
+ </ScrollView>
599
+ {!loading && !error && product && (
600
+ <ProductActions style={{ maxHeight: windowHeight * 0.15 }}>
601
+ <OText size={16} lineHeight={24} weight={'600'}>
602
+ {productCart.total ? parsePrice(productCart?.total) : ''}
603
+ </OText>
604
+ {productCart && !isSoldOut && maxProductQuantity > 0 && (
605
+ <View style={styles.quantityControl}>
606
+ <TouchableOpacity
607
+ onPress={decrement}
608
+ disabled={productCart.quantity === 1 || isSoldOut}>
609
+ <OIcon
610
+ src={theme.images.general.minus}
611
+ width={16}
612
+ color={
613
+ productCart.quantity === 1 || isSoldOut
614
+ ? theme.colors.backgroundGray
615
+ : theme.colors.backgroundDark
616
+ }
617
+ />
618
+ </TouchableOpacity>
619
+ <OText
620
+ size={12}
621
+ lineHeight={18}
622
+ style={{ minWidth: 29, textAlign: 'center' }}>
623
+ {productCart.quantity}
624
+ </OText>
625
+ <TouchableOpacity
626
+ onPress={increment}
627
+ disabled={
628
+ maxProductQuantity <= 0 ||
629
+ productCart.quantity >= maxProductQuantity ||
630
+ isSoldOut
631
+ }>
632
+ <OIcon
633
+ src={theme.images.general.plus}
634
+ width={16}
635
+ color={
636
+ maxProductQuantity <= 0 ||
637
+ productCart.quantity >= maxProductQuantity ||
638
+ isSoldOut
639
+ ? theme.colors.backgroundGray
640
+ : theme.colors.backgroundDark
641
+ }
642
+ />
643
+ </TouchableOpacity>
644
+ </View>
645
+ )}
646
+ <View
647
+ style={{
648
+ width: isSoldOut || maxProductQuantity <= 0 ? '100%' : '40%',
649
+ }}>
650
+ {productCart &&
651
+ !isSoldOut &&
652
+ maxProductQuantity > 0 &&
653
+ auth &&
654
+ orderState.options?.address_id && (
655
+ <OButton
656
+ onClick={() => handleSaveProduct()}
657
+ imgRightSrc=""
658
+ text={`${orderState.loading
659
+ ? t('LOADING', 'Loading')
660
+ : editMode
661
+ ? t('UPDATE', 'Update')
662
+ : t('ADD', 'Add')
663
+ }`}
664
+ textStyle={{
665
+ color: saveErrors ? theme.colors.primary : theme.colors.white,
666
+ }}
667
+ style={{
668
+ backgroundColor: saveErrors ? theme.colors.white : theme.colors.primary,
669
+ borderColor: saveErrors ? theme.colors.white : theme.colors.primary,
670
+ opacity: saveErrors ? 0.3 : 1,
671
+ borderRadius: 7.6,
672
+ height: 44,
673
+ shadowOpacity: 0,
674
+ borderWidth: 1,
675
+ }}
676
+ />
677
+ )}
678
+ {auth &&
679
+ !orderState.options?.address_id &&
680
+ (orderState.loading ? (
681
+ <OButton
682
+ isDisabled
683
+ text={t('LOADING', 'Loading')}
684
+ imgRightSrc=""
685
+ />
686
+ ) : (
687
+ <OButton onClick={navigation.navigate('AddressList')} />
688
+ ))}
689
+ {(!auth || isSoldOut || maxProductQuantity <= 0) && (
690
+ <OButton
691
+ isDisabled={isSoldOut || maxProductQuantity <= 0}
692
+ onClick={() => handleRedirectLogin()}
693
+ text={
694
+ isSoldOut || maxProductQuantity <= 0
695
+ ? t('SOLD_OUT', 'Sold out')
696
+ : t('LOGIN_SIGNUP', 'Login / Sign Up')
697
+ }
698
+ imgRightSrc=""
699
+ textStyle={{ color: theme.colors.primary }}
700
+ style={{
701
+ borderColor: theme.colors.primary,
702
+ backgroundColor: theme.colors.white,
703
+ }}
704
+ />
705
+ )}
706
+ </View>
707
+ </ProductActions>
708
+ )}
709
+ </>
710
+ );
685
711
  };
686
712
 
687
713
 
688
714
  export const ProductForm = (props: any) => {
689
- const productOptionsProps = {
690
- ...props,
691
- UIComponent: ProductOptionsUI,
692
- };
715
+ const productOptionsProps = {
716
+ ...props,
717
+ UIComponent: ProductOptionsUI,
718
+ };
693
719
 
694
- return <ProductOptions {...productOptionsProps} />;
720
+ return <ProductOptions {...productOptionsProps} />;
695
721
  };