srs-heritage-chatbot 1.0.0

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