react-native-srschat 0.1.83 → 0.1.85
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/lib/commonjs/components/email.js +5 -9
- package/lib/commonjs/components/email.js.map +1 -1
- package/lib/commonjs/components/productCard.js +91 -86
- package/lib/commonjs/components/productCard.js.map +1 -1
- package/lib/commonjs/components/welcomeButton.js +4 -4
- package/lib/commonjs/components/welcomeButton.js.map +1 -1
- package/lib/commonjs/contexts/AppContext.js +46 -45
- package/lib/commonjs/contexts/AppContext.js.map +1 -1
- package/lib/commonjs/hooks/Stream.js +399 -74
- package/lib/commonjs/hooks/Stream.js.map +1 -1
- package/lib/commonjs/layout/disclaimer.js +36 -32
- package/lib/commonjs/layout/disclaimer.js.map +1 -1
- package/lib/commonjs/layout/welcome.js +8 -7
- package/lib/commonjs/layout/welcome.js.map +1 -1
- package/lib/commonjs/layout/window.js +152 -131
- package/lib/commonjs/layout/window.js.map +1 -1
- package/lib/commonjs/utils/audioRecorder.js.map +1 -1
- package/lib/commonjs/utils/storage.js +1 -1
- package/lib/module/components/email.js +5 -9
- package/lib/module/components/email.js.map +1 -1
- package/lib/module/components/productCard.js +94 -89
- package/lib/module/components/productCard.js.map +1 -1
- package/lib/module/components/welcomeButton.js +4 -4
- package/lib/module/components/welcomeButton.js.map +1 -1
- package/lib/module/contexts/AppContext.js +47 -46
- package/lib/module/contexts/AppContext.js.map +1 -1
- package/lib/module/hooks/Stream.js +400 -75
- package/lib/module/hooks/Stream.js.map +1 -1
- package/lib/module/layout/disclaimer.js +41 -37
- package/lib/module/layout/disclaimer.js.map +1 -1
- package/lib/module/layout/welcome.js +8 -7
- package/lib/module/layout/welcome.js.map +1 -1
- package/lib/module/layout/window.js +152 -131
- package/lib/module/layout/window.js.map +1 -1
- package/lib/module/utils/audioRecorder.js.map +1 -1
- package/lib/module/utils/storage.js +1 -1
- package/lib/typescript/components/email.d.ts.map +1 -1
- package/lib/typescript/components/productCard.d.ts +1 -1
- package/lib/typescript/components/productCard.d.ts.map +1 -1
- package/lib/typescript/components/welcomeButton.d.ts.map +1 -1
- package/lib/typescript/contexts/AppContext.d.ts +2 -2
- package/lib/typescript/contexts/AppContext.d.ts.map +1 -1
- package/lib/typescript/hooks/Stream.d.ts.map +1 -1
- package/lib/typescript/layout/disclaimer.d.ts +1 -1
- package/lib/typescript/layout/disclaimer.d.ts.map +1 -1
- package/lib/typescript/layout/welcome.d.ts.map +1 -1
- package/lib/typescript/layout/window.d.ts.map +1 -1
- package/lib/typescript/utils/audioRecorder.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/components/email.js +4 -16
- package/src/components/productCard.js +279 -203
- package/src/components/welcomeButton.js +10 -10
- package/src/contexts/AppContext.js +185 -106
- package/src/hooks/Stream.js +607 -237
- package/src/layout/disclaimer.js +125 -78
- package/src/layout/welcome.js +58 -20
- package/src/layout/window.js +279 -140
- package/src/utils/audioRecorder.js +40 -34
- package/src/utils/storage.ts +2 -2
|
@@ -1,13 +1,32 @@
|
|
|
1
|
-
import React, { useState, useContext, useEffect } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import React, { useState, useContext, useEffect } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
Image,
|
|
6
|
+
TouchableOpacity,
|
|
7
|
+
TextInput,
|
|
8
|
+
StyleSheet,
|
|
9
|
+
Platform,
|
|
10
|
+
Keyboard,
|
|
11
|
+
ActionSheetIOS,
|
|
12
|
+
Alert,
|
|
13
|
+
} from 'react-native';
|
|
14
|
+
import { AppContext } from '../contexts/AppContext';
|
|
4
15
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
|
5
16
|
|
|
6
|
-
|
|
7
17
|
export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
8
|
-
|
|
9
|
-
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
console.log('What is prod: ', prod);
|
|
20
|
+
}, []);
|
|
10
21
|
|
|
22
|
+
const {
|
|
23
|
+
onProductCardClick,
|
|
24
|
+
onAddToCartClick,
|
|
25
|
+
sessionId,
|
|
26
|
+
data,
|
|
27
|
+
ADD_TO_CART_URL,
|
|
28
|
+
} = useContext(AppContext);
|
|
29
|
+
const [keyboardVisible, setKeyboardVisible] = useState(false);
|
|
11
30
|
// Validation: Check for incomplete product information
|
|
12
31
|
const hasValidProductDetails = () => {
|
|
13
32
|
if (!prod || !prod.product_details) {
|
|
@@ -37,16 +56,18 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
37
56
|
// Check if at least one UOM has valid pricing
|
|
38
57
|
const hasValidPricing = uomKeys.some(uom => {
|
|
39
58
|
const uomInfo = uomData[uom];
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
return (
|
|
60
|
+
uomInfo &&
|
|
61
|
+
typeof uomInfo.gross_price === 'number' &&
|
|
62
|
+
uomInfo.gross_price > 0
|
|
63
|
+
);
|
|
43
64
|
});
|
|
44
65
|
|
|
45
66
|
return hasValidPricing;
|
|
46
67
|
};
|
|
47
68
|
|
|
48
69
|
// Return null if product lacks essential information
|
|
49
|
-
if (!hasValidProductDetails()
|
|
70
|
+
if (!hasValidProductDetails()) {
|
|
50
71
|
return null;
|
|
51
72
|
}
|
|
52
73
|
|
|
@@ -56,11 +77,11 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
56
77
|
const defaultUom = prod.inventory_info.default_uom;
|
|
57
78
|
return availableUoms.includes(defaultUom) ? defaultUom : availableUoms[0];
|
|
58
79
|
}
|
|
59
|
-
return
|
|
80
|
+
return 'EA';
|
|
60
81
|
});
|
|
61
82
|
|
|
62
83
|
// Helper function to get min_pack_qty, defaulting to 1 if not applicable
|
|
63
|
-
const getMinPackQtyForUom =
|
|
84
|
+
const getMinPackQtyForUom = uomKey => {
|
|
64
85
|
const minPackStr = prod.inventory_info?.info_by_uom?.[uomKey]?.min_pack_qty;
|
|
65
86
|
if (minPackStr) {
|
|
66
87
|
const minPackNum = parseFloat(minPackStr);
|
|
@@ -74,25 +95,30 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
74
95
|
|
|
75
96
|
const uoms = prod.inventory_info?.info_by_uom
|
|
76
97
|
? Object.keys(prod.inventory_info.info_by_uom)
|
|
77
|
-
: [
|
|
78
|
-
|
|
98
|
+
: ['EA'];
|
|
99
|
+
|
|
79
100
|
const uomInfo = prod.inventory_info?.info_by_uom?.[selectedUom] || {};
|
|
80
101
|
const grossPrice = uomInfo.gross_price || 0;
|
|
81
102
|
const netPrice = uomInfo.net_price || 0;
|
|
82
103
|
const isOnSale = uomInfo.is_on_sale || false;
|
|
83
|
-
const discountsArray = Array.isArray(uomInfo.discounts)
|
|
84
|
-
|
|
85
|
-
|
|
104
|
+
const discountsArray = Array.isArray(uomInfo.discounts)
|
|
105
|
+
? uomInfo.discounts
|
|
106
|
+
: [];
|
|
107
|
+
const discountsString = uomInfo.discounts ? uomInfo.discounts : '';
|
|
108
|
+
|
|
86
109
|
// maxQuantity is for display purposes only now
|
|
87
|
-
const maxQuantity = Math.floor(uomInfo.quantity_available || 0);
|
|
110
|
+
const maxQuantity = Math.floor(uomInfo.quantity_available || 0);
|
|
88
111
|
const valid = prod.inventory_info?.is_valid || false;
|
|
112
|
+
|
|
113
|
+
console.log(prod.inventory_info);
|
|
114
|
+
|
|
89
115
|
// inStock is for display purposes or if specific logic still needs it, but not for quantity restriction
|
|
90
|
-
const inStock = maxQuantity > 0;
|
|
91
|
-
|
|
116
|
+
const inStock = maxQuantity > 0;
|
|
117
|
+
|
|
92
118
|
const currentMinPackQtyForSelectedUom = getMinPackQtyForUom(selectedUom);
|
|
93
119
|
|
|
94
120
|
const [quantity, setQuantity] = useState(0);
|
|
95
|
-
const [quantityText, setQuantityText] = useState(
|
|
121
|
+
const [quantityText, setQuantityText] = useState('0'); // Track the text input separately
|
|
96
122
|
|
|
97
123
|
// Add keyboard listeners to detect when keyboard appears/disappears
|
|
98
124
|
useEffect(() => {
|
|
@@ -104,14 +130,14 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
104
130
|
if (onFocusQuantityInput) {
|
|
105
131
|
onFocusQuantityInput(prod.part_number);
|
|
106
132
|
}
|
|
107
|
-
}
|
|
133
|
+
},
|
|
108
134
|
);
|
|
109
|
-
|
|
135
|
+
|
|
110
136
|
const keyboardDidHideListener = Keyboard.addListener(
|
|
111
137
|
'keyboardDidHide',
|
|
112
138
|
() => {
|
|
113
139
|
setKeyboardVisible(false);
|
|
114
|
-
}
|
|
140
|
+
},
|
|
115
141
|
);
|
|
116
142
|
|
|
117
143
|
return () => {
|
|
@@ -121,31 +147,31 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
121
147
|
}, []);
|
|
122
148
|
|
|
123
149
|
// Called on every keystroke in the quantity input
|
|
124
|
-
const handleQuantityChange =
|
|
150
|
+
const handleQuantityChange = text => {
|
|
125
151
|
const rawValue = text.trim();
|
|
126
|
-
|
|
152
|
+
|
|
127
153
|
// Update the text display immediately
|
|
128
154
|
setQuantityText(rawValue);
|
|
129
|
-
|
|
155
|
+
|
|
130
156
|
// Handle empty input
|
|
131
|
-
if (rawValue ===
|
|
132
|
-
|
|
133
|
-
|
|
157
|
+
if (rawValue === '') {
|
|
158
|
+
setQuantity(0);
|
|
159
|
+
return;
|
|
134
160
|
}
|
|
135
|
-
|
|
161
|
+
|
|
136
162
|
// Allow partial decimal inputs like "." or "1."
|
|
137
|
-
if (rawValue ===
|
|
138
|
-
|
|
139
|
-
|
|
163
|
+
if (rawValue === '.' || rawValue.endsWith('.')) {
|
|
164
|
+
// Don't update quantity state for partial decimal inputs, just keep the text
|
|
165
|
+
return;
|
|
140
166
|
}
|
|
141
|
-
|
|
167
|
+
|
|
142
168
|
const numericValue = parseFloat(rawValue);
|
|
143
169
|
if (!isNaN(numericValue) && numericValue >= 0) {
|
|
144
|
-
|
|
145
|
-
|
|
170
|
+
// Round to 2 decimal places to handle decimal min pack quantities
|
|
171
|
+
setQuantity(Math.round(numericValue * 100) / 100);
|
|
146
172
|
} else {
|
|
147
|
-
|
|
148
|
-
|
|
173
|
+
// Invalid input, reset quantity but keep the text for user feedback
|
|
174
|
+
setQuantity(0);
|
|
149
175
|
}
|
|
150
176
|
};
|
|
151
177
|
|
|
@@ -156,32 +182,32 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
156
182
|
// Parse the final text input
|
|
157
183
|
const rawValue = quantityText.trim();
|
|
158
184
|
let finalQuantity = 0;
|
|
159
|
-
|
|
160
|
-
if (rawValue !==
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
185
|
+
|
|
186
|
+
if (rawValue !== '') {
|
|
187
|
+
const numericValue = parseFloat(rawValue);
|
|
188
|
+
if (!isNaN(numericValue) && numericValue >= 0) {
|
|
189
|
+
finalQuantity = Math.round(numericValue * 100) / 100;
|
|
190
|
+
}
|
|
165
191
|
}
|
|
166
192
|
|
|
167
193
|
// Only basic validation - don't auto-correct to min pack quantities
|
|
168
194
|
if (!isProdValid) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
195
|
+
setQuantity(0);
|
|
196
|
+
setQuantityText('0');
|
|
197
|
+
return;
|
|
172
198
|
}
|
|
173
199
|
|
|
174
200
|
// Just ensure quantity is not negative, but allow any positive decimal value
|
|
175
201
|
if (finalQuantity < 0) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
202
|
+
setQuantity(0);
|
|
203
|
+
setQuantityText('0');
|
|
204
|
+
return;
|
|
179
205
|
}
|
|
180
206
|
|
|
181
207
|
// Update both states with the final parsed value
|
|
182
208
|
setQuantity(finalQuantity);
|
|
183
209
|
setQuantityText(finalQuantity.toString());
|
|
184
|
-
|
|
210
|
+
|
|
185
211
|
// Keep the user's input as-is for valid products
|
|
186
212
|
// Validation and alerts will happen in handleAddToCart
|
|
187
213
|
};
|
|
@@ -189,10 +215,10 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
189
215
|
const incrementQuantity = () => {
|
|
190
216
|
const uomForCalc = selectedUom;
|
|
191
217
|
const minPackForUom = getMinPackQtyForUom(uomForCalc);
|
|
192
|
-
|
|
218
|
+
|
|
193
219
|
setQuantity(prevQuantity => {
|
|
194
220
|
let newQuantity;
|
|
195
|
-
|
|
221
|
+
|
|
196
222
|
if (prevQuantity === 0) {
|
|
197
223
|
// If starting from 0, go to first min pack
|
|
198
224
|
newQuantity = minPackForUom;
|
|
@@ -201,7 +227,8 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
201
227
|
newQuantity = prevQuantity + minPackForUom;
|
|
202
228
|
} else {
|
|
203
229
|
// Find the next valid multiple of min pack quantity
|
|
204
|
-
const nextMultiple =
|
|
230
|
+
const nextMultiple =
|
|
231
|
+
Math.ceil(prevQuantity / minPackForUom) * minPackForUom;
|
|
205
232
|
// If current quantity is already a perfect multiple, go to next multiple
|
|
206
233
|
if (Math.abs(prevQuantity % minPackForUom) < 0.01) {
|
|
207
234
|
newQuantity = prevQuantity + minPackForUom;
|
|
@@ -223,19 +250,20 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
223
250
|
|
|
224
251
|
setQuantity(prevQuantity => {
|
|
225
252
|
if (prevQuantity === 0) {
|
|
226
|
-
setQuantityText(
|
|
253
|
+
setQuantityText('0');
|
|
227
254
|
return 0; // Cannot go below 0
|
|
228
255
|
}
|
|
229
256
|
|
|
230
257
|
let newQuantity;
|
|
231
|
-
|
|
258
|
+
|
|
232
259
|
if (minPackForUom <= 1) {
|
|
233
260
|
// If min pack is 1 or less, just decrement by min pack
|
|
234
261
|
newQuantity = Math.max(0, prevQuantity - minPackForUom);
|
|
235
262
|
} else {
|
|
236
263
|
// Find the previous valid multiple of min pack quantity
|
|
237
|
-
const prevMultiple =
|
|
238
|
-
|
|
264
|
+
const prevMultiple =
|
|
265
|
+
Math.floor(prevQuantity / minPackForUom) * minPackForUom;
|
|
266
|
+
|
|
239
267
|
// If current quantity is already a perfect multiple, go to previous multiple
|
|
240
268
|
if (Math.abs(prevQuantity % minPackForUom) < 0.01) {
|
|
241
269
|
newQuantity = Math.max(0, prevQuantity - minPackForUom);
|
|
@@ -244,7 +272,7 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
244
272
|
newQuantity = prevMultiple;
|
|
245
273
|
}
|
|
246
274
|
}
|
|
247
|
-
|
|
275
|
+
|
|
248
276
|
// Round to 2 decimal places to handle decimal min pack quantities
|
|
249
277
|
const finalQuantity = Math.round(newQuantity * 100) / 100;
|
|
250
278
|
setQuantityText(finalQuantity.toString());
|
|
@@ -253,25 +281,29 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
253
281
|
};
|
|
254
282
|
|
|
255
283
|
const handleAddToCart = () => {
|
|
256
|
-
if (!valid
|
|
284
|
+
if (!valid) {
|
|
257
285
|
return;
|
|
258
286
|
}
|
|
259
287
|
|
|
260
|
-
const executeAddToCartLogic =
|
|
288
|
+
const executeAddToCartLogic = qtyToAdd => {
|
|
261
289
|
try {
|
|
262
|
-
const discount = discountsString
|
|
290
|
+
const discount = discountsString
|
|
291
|
+
? discountsString
|
|
292
|
+
: Array.isArray(discountsArray)
|
|
293
|
+
? discountsArray.join(', ')
|
|
294
|
+
: '';
|
|
263
295
|
const payload = {
|
|
264
296
|
product_name: prod.product_details.product_name,
|
|
265
297
|
time_stamp: new Date().toISOString(),
|
|
266
298
|
user_id: data.user_id,
|
|
267
|
-
session_id
|
|
299
|
+
session_id: data.session_id || data.session || sessionId,
|
|
268
300
|
quantity: qtyToAdd,
|
|
269
301
|
uom: selectedUom,
|
|
270
302
|
is_sale: isOnSale,
|
|
271
303
|
discount_string: discount,
|
|
272
|
-
message_id: messageId
|
|
304
|
+
message_id: messageId,
|
|
273
305
|
};
|
|
274
|
-
console.log(
|
|
306
|
+
console.log('add to cart payload', payload);
|
|
275
307
|
fetch(ADD_TO_CART_URL, {
|
|
276
308
|
method: 'POST',
|
|
277
309
|
headers: {
|
|
@@ -286,18 +318,18 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
286
318
|
return response.json();
|
|
287
319
|
})
|
|
288
320
|
.then(data => {
|
|
289
|
-
console.log(
|
|
321
|
+
console.log('log addToCart response', data);
|
|
290
322
|
})
|
|
291
323
|
.catch(error => {
|
|
292
|
-
console.log(
|
|
324
|
+
console.log('log addToCart error', error);
|
|
293
325
|
});
|
|
294
326
|
} catch (error) {
|
|
295
|
-
console.log(
|
|
327
|
+
console.log('log addToCart error', error);
|
|
296
328
|
}
|
|
297
329
|
onAddToCartClick({
|
|
298
330
|
selectedUom: selectedUom,
|
|
299
331
|
quantity: qtyToAdd,
|
|
300
|
-
product: prod
|
|
332
|
+
product: prod,
|
|
301
333
|
});
|
|
302
334
|
};
|
|
303
335
|
|
|
@@ -306,12 +338,20 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
306
338
|
if (requestedQty <= 0) {
|
|
307
339
|
requestedQty = 1;
|
|
308
340
|
setQuantity(1);
|
|
309
|
-
setQuantityText(
|
|
341
|
+
setQuantityText('1');
|
|
310
342
|
}
|
|
311
343
|
|
|
312
344
|
// Check if quantity is valid for min pack requirements
|
|
313
|
-
if (
|
|
314
|
-
|
|
345
|
+
if (
|
|
346
|
+
currentMinPackQtyForSelectedUom > 1 &&
|
|
347
|
+
Math.abs(requestedQty % currentMinPackQtyForSelectedUom) > 0.01
|
|
348
|
+
) {
|
|
349
|
+
const roundedResult =
|
|
350
|
+
Math.round(
|
|
351
|
+
Math.ceil(requestedQty / currentMinPackQtyForSelectedUom) *
|
|
352
|
+
currentMinPackQtyForSelectedUom *
|
|
353
|
+
100,
|
|
354
|
+
) / 100;
|
|
315
355
|
|
|
316
356
|
Alert.alert(
|
|
317
357
|
`Item #${prod.part_number} is sold in multiples of ${currentMinPackQtyForSelectedUom} ${selectedUom}`,
|
|
@@ -332,7 +372,7 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
332
372
|
},
|
|
333
373
|
},
|
|
334
374
|
],
|
|
335
|
-
{ cancelable: true } // User can dismiss the alert by tapping outside on Android
|
|
375
|
+
{ cancelable: true }, // User can dismiss the alert by tapping outside on Android
|
|
336
376
|
);
|
|
337
377
|
} else {
|
|
338
378
|
// No rounding needed, or item is sold individually (min pack <= 1)
|
|
@@ -340,24 +380,24 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
340
380
|
executeAddToCartLogic(requestedQty);
|
|
341
381
|
}
|
|
342
382
|
};
|
|
343
|
-
|
|
383
|
+
|
|
344
384
|
const handleProductClick = () => {
|
|
345
385
|
const prodWithSku = {
|
|
346
|
-
|
|
347
|
-
|
|
386
|
+
...prod,
|
|
387
|
+
sku: prod.product_details.sku, // Using the SKU from product_details
|
|
348
388
|
};
|
|
349
|
-
console.log(
|
|
350
|
-
onProductCardClick(prodWithSku);
|
|
389
|
+
console.log('Product clicked:', JSON.stringify(prodWithSku, null, 2));
|
|
390
|
+
onProductCardClick(prodWithSku);
|
|
351
391
|
};
|
|
352
|
-
|
|
353
|
-
const handleUomChange =
|
|
354
|
-
setSelectedUom(newUom);
|
|
392
|
+
|
|
393
|
+
const handleUomChange = newUom => {
|
|
394
|
+
setSelectedUom(newUom);
|
|
355
395
|
|
|
356
396
|
// Always set quantity to 0 when UOM changes
|
|
357
397
|
setQuantity(0);
|
|
358
|
-
setQuantityText(
|
|
398
|
+
setQuantityText('0');
|
|
359
399
|
};
|
|
360
|
-
|
|
400
|
+
|
|
361
401
|
const openUomPicker = () => {
|
|
362
402
|
if (Platform.OS === 'ios') {
|
|
363
403
|
ActionSheetIOS.showActionSheetWithOptions(
|
|
@@ -366,34 +406,29 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
366
406
|
cancelButtonIndex: uoms.length,
|
|
367
407
|
title: 'Select Unit',
|
|
368
408
|
},
|
|
369
|
-
|
|
409
|
+
buttonIndex => {
|
|
370
410
|
if (buttonIndex !== uoms.length) {
|
|
371
411
|
handleUomChange(uoms[buttonIndex]);
|
|
372
412
|
}
|
|
373
|
-
}
|
|
413
|
+
},
|
|
374
414
|
);
|
|
375
415
|
} else if (Platform.OS === 'android') {
|
|
376
416
|
// Android implementation
|
|
377
417
|
const buttons = uoms.map(uom => ({
|
|
378
418
|
text: uom,
|
|
379
|
-
onPress: () => handleUomChange(uom)
|
|
419
|
+
onPress: () => handleUomChange(uom),
|
|
380
420
|
}));
|
|
381
|
-
|
|
421
|
+
|
|
382
422
|
// Add cancel button
|
|
383
423
|
buttons.push({
|
|
384
424
|
text: 'Cancel',
|
|
385
|
-
style: 'cancel'
|
|
425
|
+
style: 'cancel',
|
|
386
426
|
});
|
|
387
|
-
|
|
388
|
-
Alert.alert(
|
|
389
|
-
'Select Unit',
|
|
390
|
-
'',
|
|
391
|
-
buttons,
|
|
392
|
-
{ cancelable: true }
|
|
393
|
-
);
|
|
427
|
+
|
|
428
|
+
Alert.alert('Select Unit', '', buttons, { cancelable: true });
|
|
394
429
|
}
|
|
395
430
|
};
|
|
396
|
-
|
|
431
|
+
|
|
397
432
|
return (
|
|
398
433
|
<View style={styles.card}>
|
|
399
434
|
{/* Two-column layout */}
|
|
@@ -406,53 +441,89 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
406
441
|
<Text style={styles.saleTagText}>SALE</Text>
|
|
407
442
|
</View>
|
|
408
443
|
)}
|
|
409
|
-
<Image
|
|
444
|
+
<Image
|
|
445
|
+
source={
|
|
446
|
+
prod.product_details.image_url
|
|
447
|
+
? { uri: prod.product_details.image_url }
|
|
448
|
+
: require('../assets/heritage.png')
|
|
449
|
+
}
|
|
450
|
+
style={styles.image}
|
|
451
|
+
defaultSource={require('../assets/heritage.png')}
|
|
452
|
+
/>
|
|
410
453
|
</TouchableOpacity>
|
|
411
|
-
|
|
454
|
+
{valid && (
|
|
412
455
|
<>
|
|
413
|
-
|
|
456
|
+
<View style={styles.priceContainer}>
|
|
414
457
|
{isOnSale ? (
|
|
415
|
-
|
|
416
|
-
<Text style={styles.originalPrice} allowFontScaling={false}
|
|
417
|
-
|
|
458
|
+
<>
|
|
459
|
+
<Text style={styles.originalPrice} allowFontScaling={false}>
|
|
460
|
+
$
|
|
461
|
+
{Number(grossPrice).toLocaleString('en-US', {
|
|
462
|
+
minimumFractionDigits: 2,
|
|
463
|
+
maximumFractionDigits: 2,
|
|
464
|
+
})}
|
|
465
|
+
</Text>
|
|
466
|
+
<Text style={styles.salePrice} allowFontScaling={false}>
|
|
467
|
+
$
|
|
468
|
+
{Number(netPrice).toLocaleString('en-US', {
|
|
469
|
+
minimumFractionDigits: 2,
|
|
470
|
+
maximumFractionDigits: 2,
|
|
471
|
+
})}
|
|
472
|
+
</Text>
|
|
418
473
|
<Text style={styles.perUnit}>/ {selectedUom}</Text>
|
|
419
|
-
|
|
474
|
+
</>
|
|
420
475
|
) : (
|
|
421
|
-
|
|
422
|
-
<Text style={styles.price} allowFontScaling={false}
|
|
476
|
+
<>
|
|
477
|
+
<Text style={styles.price} allowFontScaling={false}>
|
|
478
|
+
$
|
|
479
|
+
{Number(grossPrice).toLocaleString('en-US', {
|
|
480
|
+
minimumFractionDigits: 2,
|
|
481
|
+
maximumFractionDigits: 2,
|
|
482
|
+
})}
|
|
483
|
+
</Text>
|
|
423
484
|
<Text style={styles.perUnit}>/ {selectedUom}</Text>
|
|
424
|
-
|
|
485
|
+
</>
|
|
425
486
|
)}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
{maxQuantity === 0
|
|
429
|
-
|
|
487
|
+
</View>
|
|
488
|
+
<Text style={styles.availability}>
|
|
489
|
+
{maxQuantity === 0
|
|
490
|
+
? '0 available'
|
|
491
|
+
: maxQuantity > 1000
|
|
492
|
+
? '1000+ available'
|
|
493
|
+
: `${maxQuantity} available`}
|
|
494
|
+
</Text>
|
|
430
495
|
</>
|
|
431
|
-
|
|
496
|
+
)}
|
|
432
497
|
</View>
|
|
433
498
|
|
|
434
499
|
{/* Right Column (Product Details) */}
|
|
435
500
|
<View style={styles.rightColumn}>
|
|
436
501
|
<TouchableOpacity onPress={handleProductClick}>
|
|
437
|
-
<Text style={styles.productName}>
|
|
502
|
+
<Text style={styles.productName}>
|
|
503
|
+
{prod.product_details.product_name}
|
|
504
|
+
</Text>
|
|
438
505
|
</TouchableOpacity>
|
|
439
506
|
|
|
440
507
|
<Text style={styles.details}>
|
|
441
|
-
<Text style={styles.boldText}>MFG # </Text>
|
|
508
|
+
<Text style={styles.boldText}>MFG # </Text>
|
|
509
|
+
{prod.product_details.manufacturer_id}
|
|
442
510
|
</Text>
|
|
443
511
|
<Text style={styles.details}>
|
|
444
|
-
<Text style={styles.boldText}>Part # </Text>
|
|
512
|
+
<Text style={styles.boldText}>Part # </Text>
|
|
513
|
+
{prod.part_number}
|
|
445
514
|
</Text>
|
|
446
515
|
|
|
447
516
|
{/* Display discounts if available */}
|
|
448
517
|
{discountsArray.length > 0 && (
|
|
449
518
|
<View style={styles.discountContainer}>
|
|
450
519
|
{discountsArray.map((discount, index) => (
|
|
451
|
-
<Text key={index} style={styles.discountText}>
|
|
520
|
+
<Text key={index} style={styles.discountText}>
|
|
521
|
+
{discount}
|
|
522
|
+
</Text>
|
|
452
523
|
))}
|
|
453
524
|
</View>
|
|
454
525
|
)}
|
|
455
|
-
{discountsString == 0 && discountsString !==
|
|
526
|
+
{discountsString == 0 && discountsString !== '' && (
|
|
456
527
|
<Text style={styles.discountText}>{discountsString}</Text>
|
|
457
528
|
)}
|
|
458
529
|
|
|
@@ -461,33 +532,36 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
461
532
|
{uoms.length > 1 ? (
|
|
462
533
|
<View style={styles.uomSelectorContainer}>
|
|
463
534
|
<Text style={styles.inputLabel}>Unit</Text>
|
|
464
|
-
<TouchableOpacity
|
|
535
|
+
<TouchableOpacity
|
|
465
536
|
style={styles.dropdownButton}
|
|
466
537
|
onPress={openUomPicker}
|
|
467
|
-
disabled={!valid}
|
|
468
|
-
>
|
|
538
|
+
disabled={!valid}>
|
|
469
539
|
<Text style={styles.dropdownButtonText}>{selectedUom}</Text>
|
|
470
540
|
</TouchableOpacity>
|
|
471
541
|
</View>
|
|
472
542
|
) : null}
|
|
473
|
-
|
|
543
|
+
|
|
474
544
|
<View style={styles.quantityContainer}>
|
|
475
545
|
<Text style={styles.inputLabel}>
|
|
476
|
-
Qty
|
|
546
|
+
Qty{' '}
|
|
547
|
+
{currentMinPackQtyForSelectedUom > 1
|
|
548
|
+
? `(Sold in multiples of ${currentMinPackQtyForSelectedUom})`
|
|
549
|
+
: ''}
|
|
477
550
|
</Text>
|
|
478
551
|
<View style={styles.quantityInputContainer}>
|
|
479
|
-
<TouchableOpacity
|
|
552
|
+
<TouchableOpacity
|
|
480
553
|
style={styles.quantityButton}
|
|
481
554
|
onPress={decrementQuantity}
|
|
482
|
-
disabled={!valid || quantity <= 0}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
555
|
+
disabled={!valid || quantity <= 0}>
|
|
556
|
+
<Ionicons
|
|
557
|
+
name="remove"
|
|
558
|
+
size={18}
|
|
559
|
+
color={
|
|
560
|
+
valid && quantity > 0 ? '#367cb6' : 'rgba(0, 0, 0, 0.23)'
|
|
561
|
+
}
|
|
488
562
|
/>
|
|
489
563
|
</TouchableOpacity>
|
|
490
|
-
|
|
564
|
+
|
|
491
565
|
<TextInput
|
|
492
566
|
value={quantityText}
|
|
493
567
|
onChangeText={handleQuantityChange}
|
|
@@ -503,16 +577,15 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
503
577
|
disableFullscreenUI={true}
|
|
504
578
|
defaultValue="0"
|
|
505
579
|
/>
|
|
506
|
-
|
|
507
|
-
<TouchableOpacity
|
|
580
|
+
|
|
581
|
+
<TouchableOpacity
|
|
508
582
|
style={styles.quantityButton}
|
|
509
583
|
onPress={incrementQuantity}
|
|
510
|
-
disabled={!valid}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
color={valid ? "#367cb6" : "rgba(0, 0, 0, 0.23)"}
|
|
584
|
+
disabled={!valid}>
|
|
585
|
+
<Ionicons
|
|
586
|
+
name="add"
|
|
587
|
+
size={18}
|
|
588
|
+
color={valid ? '#367cb6' : 'rgba(0, 0, 0, 0.23)'}
|
|
516
589
|
/>
|
|
517
590
|
</TouchableOpacity>
|
|
518
591
|
</View>
|
|
@@ -520,15 +593,18 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
520
593
|
</View>
|
|
521
594
|
|
|
522
595
|
{/* Add to Cart Button on a new line */}
|
|
523
|
-
<TouchableOpacity
|
|
524
|
-
onPress={handleAddToCart}
|
|
596
|
+
<TouchableOpacity
|
|
597
|
+
onPress={handleAddToCart}
|
|
525
598
|
disabled={!valid}
|
|
526
599
|
style={[
|
|
527
600
|
styles.addToCartButton,
|
|
528
|
-
valid ? styles.activeButton : styles.disabledButton
|
|
529
|
-
]}
|
|
530
|
-
|
|
531
|
-
|
|
601
|
+
valid ? styles.activeButton : styles.disabledButton,
|
|
602
|
+
]}>
|
|
603
|
+
<Text
|
|
604
|
+
style={[
|
|
605
|
+
styles.buttonText,
|
|
606
|
+
valid ? styles.activeText : styles.disabledText,
|
|
607
|
+
]}>
|
|
532
608
|
Add to Cart
|
|
533
609
|
</Text>
|
|
534
610
|
</TouchableOpacity>
|
|
@@ -540,110 +616,110 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
|
|
|
540
616
|
|
|
541
617
|
const styles = StyleSheet.create({
|
|
542
618
|
card: {
|
|
543
|
-
backgroundColor:
|
|
619
|
+
backgroundColor: '#fff',
|
|
544
620
|
width: '100%',
|
|
545
621
|
padding: 12,
|
|
546
622
|
paddingHorizontal: 16,
|
|
547
623
|
borderRadius: 12,
|
|
548
|
-
marginBottom: 5
|
|
624
|
+
marginBottom: 5,
|
|
549
625
|
},
|
|
550
626
|
row: {
|
|
551
|
-
flexDirection:
|
|
552
|
-
alignItems:
|
|
627
|
+
flexDirection: 'row',
|
|
628
|
+
alignItems: 'flex-start',
|
|
553
629
|
},
|
|
554
630
|
leftColumn: {
|
|
555
|
-
width:
|
|
556
|
-
alignItems:
|
|
557
|
-
position:
|
|
631
|
+
width: '25%',
|
|
632
|
+
alignItems: 'center',
|
|
633
|
+
position: 'relative',
|
|
558
634
|
},
|
|
559
635
|
rightColumn: {
|
|
560
|
-
width:
|
|
636
|
+
width: '75%',
|
|
561
637
|
paddingLeft: 12,
|
|
562
638
|
},
|
|
563
639
|
image: {
|
|
564
640
|
width: 80,
|
|
565
641
|
height: 80,
|
|
566
|
-
resizeMode:
|
|
642
|
+
resizeMode: 'contain',
|
|
567
643
|
marginBottom: 5,
|
|
568
644
|
},
|
|
569
645
|
saleTag: {
|
|
570
|
-
position:
|
|
646
|
+
position: 'absolute',
|
|
571
647
|
top: 0,
|
|
572
648
|
left: 0,
|
|
573
|
-
backgroundColor:
|
|
649
|
+
backgroundColor: 'red',
|
|
574
650
|
borderRadius: 4,
|
|
575
651
|
paddingVertical: 2,
|
|
576
652
|
paddingHorizontal: 5,
|
|
577
653
|
zIndex: 1,
|
|
578
654
|
},
|
|
579
655
|
saleTagText: {
|
|
580
|
-
color:
|
|
656
|
+
color: '#fff',
|
|
581
657
|
fontSize: 10,
|
|
582
|
-
fontWeight:
|
|
658
|
+
fontWeight: 'bold',
|
|
583
659
|
},
|
|
584
660
|
price: {
|
|
585
661
|
fontSize: 14,
|
|
586
|
-
fontWeight:
|
|
587
|
-
color:
|
|
588
|
-
textAlign:
|
|
589
|
-
textBreakStrategy:
|
|
590
|
-
alignSelf:
|
|
662
|
+
fontWeight: 'bold',
|
|
663
|
+
color: '#161616',
|
|
664
|
+
textAlign: 'center',
|
|
665
|
+
textBreakStrategy: 'simple',
|
|
666
|
+
alignSelf: 'stretch',
|
|
591
667
|
lineHeight: 20,
|
|
592
668
|
includeFontPadding: false,
|
|
593
669
|
textAlignVertical: 'center',
|
|
594
670
|
},
|
|
595
671
|
priceContainer: {
|
|
596
|
-
flexDirection:
|
|
597
|
-
alignItems:
|
|
598
|
-
justifyContent:
|
|
672
|
+
flexDirection: 'column',
|
|
673
|
+
alignItems: 'center',
|
|
674
|
+
justifyContent: 'center',
|
|
599
675
|
paddingHorizontal: 2,
|
|
600
676
|
},
|
|
601
677
|
originalPrice: {
|
|
602
678
|
fontSize: 14,
|
|
603
|
-
textDecorationLine:
|
|
604
|
-
color:
|
|
605
|
-
textAlign:
|
|
606
|
-
textBreakStrategy:
|
|
679
|
+
textDecorationLine: 'line-through',
|
|
680
|
+
color: 'gray',
|
|
681
|
+
textAlign: 'center',
|
|
682
|
+
textBreakStrategy: 'simple',
|
|
607
683
|
lineHeight: 20,
|
|
608
684
|
includeFontPadding: false,
|
|
609
685
|
textAlignVertical: 'center',
|
|
610
686
|
},
|
|
611
687
|
salePrice: {
|
|
612
688
|
fontSize: 16,
|
|
613
|
-
fontWeight:
|
|
614
|
-
color:
|
|
615
|
-
textAlign:
|
|
616
|
-
textBreakStrategy:
|
|
689
|
+
fontWeight: 'bold',
|
|
690
|
+
color: 'red',
|
|
691
|
+
textAlign: 'center',
|
|
692
|
+
textBreakStrategy: 'simple',
|
|
617
693
|
lineHeight: 22,
|
|
618
694
|
includeFontPadding: false,
|
|
619
695
|
textAlignVertical: 'center',
|
|
620
696
|
},
|
|
621
697
|
perUnit: {
|
|
622
698
|
fontSize: 12,
|
|
623
|
-
color:
|
|
624
|
-
textAlign:
|
|
699
|
+
color: 'gray',
|
|
700
|
+
textAlign: 'center',
|
|
625
701
|
},
|
|
626
702
|
availability: {
|
|
627
703
|
fontSize: 12,
|
|
628
|
-
color:
|
|
629
|
-
textAlign:
|
|
704
|
+
color: 'gray',
|
|
705
|
+
textAlign: 'center',
|
|
630
706
|
marginTop: 3,
|
|
631
707
|
},
|
|
632
708
|
productName: {
|
|
633
709
|
fontSize: 16,
|
|
634
|
-
fontWeight:
|
|
635
|
-
color:
|
|
710
|
+
fontWeight: 'medium',
|
|
711
|
+
color: '#161616',
|
|
636
712
|
marginBottom: 5,
|
|
637
|
-
textDecorationLine:
|
|
638
|
-
textDecorationColor:
|
|
713
|
+
textDecorationLine: 'underline',
|
|
714
|
+
textDecorationColor: '#367CB6',
|
|
639
715
|
},
|
|
640
716
|
details: {
|
|
641
717
|
fontSize: 13,
|
|
642
|
-
color:
|
|
718
|
+
color: '#555',
|
|
643
719
|
marginTop: 3,
|
|
644
720
|
},
|
|
645
721
|
boldText: {
|
|
646
|
-
fontWeight:
|
|
722
|
+
fontWeight: 'bold',
|
|
647
723
|
},
|
|
648
724
|
discountContainer: {
|
|
649
725
|
marginTop: 5,
|
|
@@ -651,13 +727,13 @@ const styles = StyleSheet.create({
|
|
|
651
727
|
},
|
|
652
728
|
discountText: {
|
|
653
729
|
fontSize: 13,
|
|
654
|
-
color:
|
|
655
|
-
fontWeight:
|
|
730
|
+
color: '#e41e31',
|
|
731
|
+
fontWeight: '500',
|
|
656
732
|
marginTop: 3,
|
|
657
733
|
},
|
|
658
734
|
inputRow: {
|
|
659
|
-
flexDirection:
|
|
660
|
-
alignItems:
|
|
735
|
+
flexDirection: 'row',
|
|
736
|
+
alignItems: 'flex-end',
|
|
661
737
|
marginTop: 10,
|
|
662
738
|
marginBottom: 10,
|
|
663
739
|
},
|
|
@@ -666,7 +742,7 @@ const styles = StyleSheet.create({
|
|
|
666
742
|
},
|
|
667
743
|
inputLabel: {
|
|
668
744
|
fontSize: 12,
|
|
669
|
-
color:
|
|
745
|
+
color: 'rgba(0, 0, 0, 0.6)',
|
|
670
746
|
marginBottom: 4,
|
|
671
747
|
},
|
|
672
748
|
dropdownButton: {
|
|
@@ -689,51 +765,51 @@ const styles = StyleSheet.create({
|
|
|
689
765
|
flex: 1,
|
|
690
766
|
},
|
|
691
767
|
quantityInputContainer: {
|
|
692
|
-
flexDirection:
|
|
693
|
-
alignItems:
|
|
768
|
+
flexDirection: 'row',
|
|
769
|
+
alignItems: 'center',
|
|
694
770
|
height: 40,
|
|
695
771
|
borderWidth: 1,
|
|
696
|
-
borderColor:
|
|
772
|
+
borderColor: 'rgba(0, 0, 0, 0.23)',
|
|
697
773
|
borderRadius: 4,
|
|
698
774
|
},
|
|
699
775
|
quantityButton: {
|
|
700
776
|
width: 40,
|
|
701
777
|
height: 40,
|
|
702
|
-
justifyContent:
|
|
703
|
-
alignItems:
|
|
778
|
+
justifyContent: 'center',
|
|
779
|
+
alignItems: 'center',
|
|
704
780
|
},
|
|
705
781
|
quantityInput: {
|
|
706
782
|
flex: 1,
|
|
707
783
|
height: 40,
|
|
708
|
-
textAlign:
|
|
784
|
+
textAlign: 'center',
|
|
709
785
|
paddingHorizontal: 5,
|
|
710
786
|
fontSize: 14,
|
|
711
787
|
minWidth: 40,
|
|
712
|
-
color:
|
|
788
|
+
color: '#000',
|
|
713
789
|
},
|
|
714
790
|
addToCartButton: {
|
|
715
791
|
height: 40,
|
|
716
|
-
justifyContent:
|
|
717
|
-
alignItems:
|
|
792
|
+
justifyContent: 'center',
|
|
793
|
+
alignItems: 'center',
|
|
718
794
|
borderRadius: 4,
|
|
719
795
|
marginTop: 5,
|
|
720
796
|
},
|
|
721
797
|
activeButton: {
|
|
722
|
-
backgroundColor:
|
|
798
|
+
backgroundColor: '#367cb6',
|
|
723
799
|
},
|
|
724
800
|
disabledButton: {
|
|
725
|
-
backgroundColor:
|
|
801
|
+
backgroundColor: 'transparent',
|
|
726
802
|
borderWidth: 1,
|
|
727
|
-
borderColor:
|
|
803
|
+
borderColor: 'rgba(0, 0, 0, 0.23)',
|
|
728
804
|
},
|
|
729
805
|
buttonText: {
|
|
730
806
|
fontSize: 14,
|
|
731
|
-
fontWeight:
|
|
807
|
+
fontWeight: 'bold',
|
|
732
808
|
},
|
|
733
809
|
activeText: {
|
|
734
|
-
color:
|
|
810
|
+
color: '#fff',
|
|
735
811
|
},
|
|
736
812
|
disabledText: {
|
|
737
|
-
color:
|
|
813
|
+
color: 'rgba(0, 0, 0, 0.60)',
|
|
738
814
|
},
|
|
739
815
|
});
|