ordering-components-external 13.2.32 → 13.2.34

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 (537) hide show
  1. package/.babelrc +22 -22
  2. package/.vscode/settings.json +3 -3
  3. package/_bundles/{7.ordering-component.5e6b244837705c07824f.js → 7.ordering-component.6cdb5ba8147ea6e69b23.js} +1 -1
  4. package/_bundles/{ordering-component.5e6b244837705c07824f.js → ordering-component.6cdb5ba8147ea6e69b23.js} +2 -2
  5. package/_modules/components/AddressDetails/index.js +26 -26
  6. package/_modules/components/AddressForm/index.js +50 -50
  7. package/_modules/components/AddressList/index.js +40 -40
  8. package/_modules/components/Analitycs/index.js +6 -6
  9. package/_modules/components/AnalyticsSegment/index.js +3 -3
  10. package/_modules/components/AppleLogin/index.js +26 -26
  11. package/_modules/components/BaseComponent/index.js +14 -14
  12. package/_modules/components/BusinessAndProductList/index.js +16 -16
  13. package/_modules/components/BusinessBasicInformation/index.js +20 -20
  14. package/_modules/components/BusinessController/index.js +50 -50
  15. package/_modules/components/BusinessInformation/BusinessOption/index.js +20 -20
  16. package/_modules/components/BusinessInformation/index.js +18 -18
  17. package/_modules/components/BusinessList/index.js +42 -42
  18. package/_modules/components/BusinessMenuListing/index.js +20 -20
  19. package/_modules/components/BusinessProductsCategories/index.js +16 -16
  20. package/_modules/components/BusinessProductsSearch/index.js +14 -14
  21. package/_modules/components/BusinessReviews/index.js +27 -27
  22. package/_modules/components/BusinessSearchList/index.js +18 -18
  23. package/_modules/components/BusinessSortControl/index.js +28 -28
  24. package/_modules/components/BusinessTypeFilter/index.js +26 -26
  25. package/_modules/components/BusinessesMap/index.js +27 -27
  26. package/_modules/components/Cart/index.js +38 -38
  27. package/_modules/components/CartStoresListing/index.js +4 -4
  28. package/_modules/components/Checkout/index.js +60 -60
  29. package/_modules/components/CmsContent/index.js +20 -20
  30. package/_modules/components/Contacts/index.js +28 -28
  31. package/_modules/components/CouponControl/index.js +22 -22
  32. package/_modules/components/DriverList/index.js +22 -22
  33. package/_modules/components/DriverTips/index.js +35 -35
  34. package/_modules/components/FacebookLoginButton/index.js +40 -40
  35. package/_modules/components/FacebookPixel/index.js +3 -3
  36. package/_modules/components/FavoriteList/index.js +28 -28
  37. package/_modules/components/FirebaseGoogleLoginButton/index.js +10 -10
  38. package/_modules/components/FloatingButton/index.js +20 -20
  39. package/_modules/components/ForgotPasswordForm/index.js +43 -43
  40. package/_modules/components/GiftCard/GiftCardOrdersList/index.js +4 -4
  41. package/_modules/components/GiftCard/PurchaseGiftCard/index.js +6 -6
  42. package/_modules/components/GiftCard/RedeemGiftCard/index.js +4 -4
  43. package/_modules/components/GiftCard/SendGiftCard/index.js +4 -4
  44. package/_modules/components/GoogleAutocompleteInput/index.js +18 -18
  45. package/_modules/components/GoogleIdentity/index.js +28 -28
  46. package/_modules/components/GoogleLoginButton/index.js +49 -49
  47. package/_modules/components/GoogleMaps/index.js +37 -37
  48. package/_modules/components/GpsButton/index.js +20 -20
  49. package/_modules/components/LanguageSelector/index.js +28 -28
  50. package/_modules/components/LoginForm/index.js +58 -58
  51. package/_modules/components/LogoutAction/index.js +17 -17
  52. package/_modules/components/MainSearch/index.js +31 -31
  53. package/_modules/components/MenuControl/index.js +51 -51
  54. package/_modules/components/Messages/index.js +22 -22
  55. package/_modules/components/MomentOption/index.js +51 -51
  56. package/_modules/components/MultiCartCreate/index.js +2 -2
  57. package/_modules/components/MultiCartsPaymethodsAndWallets/index.js +8 -8
  58. package/_modules/components/MultiCheckout/index.js +12 -12
  59. package/_modules/components/MultiOrdersDetails/index.js +6 -6
  60. package/_modules/components/MyOrders/index.js +24 -24
  61. package/_modules/components/MyOrdersList/index.js +26 -26
  62. package/_modules/components/NewOrderNotification/index.js +2 -2
  63. package/_modules/components/OrderChange/index.js +20 -20
  64. package/_modules/components/OrderDetails/index.js +43 -43
  65. package/_modules/components/OrderList/index.js +44 -44
  66. package/_modules/components/OrderReview/index.js +22 -22
  67. package/_modules/components/OrderTypeControl/index.js +18 -18
  68. package/_modules/components/OrdersControlFilters/index.js +6 -6
  69. package/_modules/components/OrdersDashboardComponents/Appointments/index.js +4 -4
  70. package/_modules/components/OrdersDashboardComponents/BusinessProductsListing/index.js +26 -26
  71. package/_modules/components/OrdersDashboardComponents/CheckPassword/index.js +24 -24
  72. package/_modules/components/OrdersDashboardComponents/CityList/index.js +20 -20
  73. package/_modules/components/OrdersDashboardComponents/CountryList/index.js +20 -20
  74. package/_modules/components/OrdersDashboardComponents/CustomOrderDetails/index.js +12 -12
  75. package/_modules/components/OrdersDashboardComponents/DashboardBusinessList/index.js +54 -54
  76. package/_modules/components/OrdersDashboardComponents/DashboardOrdersList/index.js +60 -60
  77. package/_modules/components/OrdersDashboardComponents/DriversList/index.js +58 -58
  78. package/_modules/components/OrdersDashboardComponents/ExportCSV/index.js +16 -16
  79. package/_modules/components/OrdersDashboardComponents/GiftCardsList/index.js +6 -6
  80. package/_modules/components/OrdersDashboardComponents/GoogleMapsApiKeySetting/index.js +4 -4
  81. package/_modules/components/OrdersDashboardComponents/LogisticInformation/index.js +20 -20
  82. package/_modules/components/OrdersDashboardComponents/Logistics/index.js +20 -20
  83. package/_modules/components/OrdersDashboardComponents/Messages/index.js +27 -27
  84. package/_modules/components/OrdersDashboardComponents/MetaFields/index.js +26 -26
  85. package/_modules/components/OrdersDashboardComponents/OrderDetails/index.js +36 -36
  86. package/_modules/components/OrdersDashboardComponents/OrderNotification/index.js +14 -14
  87. package/_modules/components/OrdersDashboardComponents/OrdersFilter/index.js +62 -62
  88. package/_modules/components/OrdersDashboardComponents/OrdersManage/index.js +56 -56
  89. package/_modules/components/OrdersDashboardComponents/PointsWalletLevels/index.js +25 -25
  90. package/_modules/components/OrdersDashboardComponents/ReviewCustomer/index.js +16 -16
  91. package/_modules/components/OrdersDashboardComponents/Schedule/index.js +46 -46
  92. package/_modules/components/OrdersDashboardComponents/SettingsList/index.js +39 -39
  93. package/_modules/components/OrdersDashboardComponents/UserFormDetails/index.js +66 -66
  94. package/_modules/components/OrdersDashboardComponents/UsersList/index.js +54 -54
  95. package/_modules/components/OrdersDashboardComponents/WebsocketStatus/index.js +4 -4
  96. package/_modules/components/PageBanner/index.js +4 -4
  97. package/_modules/components/PaymentOptionCash/index.js +24 -24
  98. package/_modules/components/PaymentOptionPaypal/index.js +24 -24
  99. package/_modules/components/PaymentOptionSquare/index.js +2 -2
  100. package/_modules/components/PaymentOptionStripe/index.js +32 -32
  101. package/_modules/components/PaymentOptionStripeDirect/index.js +24 -24
  102. package/_modules/components/PaymentOptionStripeLink/index.js +4 -4
  103. package/_modules/components/PaymentOptionStripeRedirect/StripeRedirectForm/index.js +19 -19
  104. package/_modules/components/PaymentOptionStripeRedirect/index.js +30 -30
  105. package/_modules/components/PaymentOptions/index.js +27 -27
  106. package/_modules/components/PaymethodList/index.js +20 -20
  107. package/_modules/components/PhoneAutocomplete/index.js +18 -18
  108. package/_modules/components/PlaceSpot/index.js +2 -2
  109. package/_modules/components/Popup/index.js +33 -33
  110. package/_modules/components/ProductComponent/index.js +27 -27
  111. package/_modules/components/ProductForm/index.js +159 -135
  112. package/_modules/components/ProductImages/index.js +18 -18
  113. package/_modules/components/ProductIngredient/index.js +17 -17
  114. package/_modules/components/ProductItemAccordion/index.js +8 -8
  115. package/_modules/components/ProductOption/index.js +8 -8
  116. package/_modules/components/ProductOptionSuboption/index.js +33 -33
  117. package/_modules/components/ProductShare/index.js +20 -20
  118. package/_modules/components/ProductsList/index.js +20 -20
  119. package/_modules/components/ProductsListing/index.js +39 -39
  120. package/_modules/components/ProfessionalInfo/index.js +24 -24
  121. package/_modules/components/QueryLoginSpoonity/index.js +20 -20
  122. package/_modules/components/ReCaptcha/index.js +4 -4
  123. package/_modules/components/ResetPassword/index.js +20 -20
  124. package/_modules/components/ReviewCustomer/index.js +16 -16
  125. package/_modules/components/ReviewDriver/index.js +20 -20
  126. package/_modules/components/ReviewProduct/index.js +22 -22
  127. package/_modules/components/SearchOptions/index.js +17 -17
  128. package/_modules/components/Sessions/index.js +21 -21
  129. package/_modules/components/SignupForm/index.js +58 -58
  130. package/_modules/components/SingleBusinessCard/index.js +28 -28
  131. package/_modules/components/SingleOrderCard/index.js +20 -20
  132. package/_modules/components/SingleProductCard/index.js +18 -18
  133. package/_modules/components/SingleProfessionalCard/index.js +18 -18
  134. package/_modules/components/SmartAppBanner/index.js +8 -8
  135. package/_modules/components/StoreProductList/index.js +22 -22
  136. package/_modules/components/StripeElementsForm/CardForm/index.js +25 -25
  137. package/_modules/components/StripeElementsForm/index.js +16 -16
  138. package/_modules/components/UpsellingPage/index.js +19 -19
  139. package/_modules/components/UserFormDetails/index.js +68 -68
  140. package/_modules/components/UserVerification/index.js +24 -17
  141. package/_modules/components/WebsocketStatus/index.js +4 -4
  142. package/_modules/components/WrapperGoogleMaps/index.js +3 -3
  143. package/_modules/contexts/ApiContext/index.js +8 -8
  144. package/_modules/contexts/BillingContext/index.js +7 -7
  145. package/_modules/contexts/BusinessContext/index.js +9 -9
  146. package/_modules/contexts/ConfigContext/index.js +9 -9
  147. package/_modules/contexts/EventContext/index.js +9 -9
  148. package/_modules/contexts/LanguageContext/index.js +13 -13
  149. package/_modules/contexts/OptimizationLoadContext/index.js +8 -8
  150. package/_modules/contexts/OrderContext/index.js +62 -62
  151. package/_modules/contexts/OrderingContext/index.js +7 -7
  152. package/_modules/contexts/OrderingThemeContext/index.js +11 -11
  153. package/_modules/contexts/ProductContext/index.js +13 -13
  154. package/_modules/contexts/SessionContext/index.js +9 -9
  155. package/_modules/contexts/SiteContext/index.js +9 -9
  156. package/_modules/contexts/UtilsContext/index.js +9 -9
  157. package/_modules/contexts/WebsocketContext/index.js +9 -9
  158. package/_modules/native/src/contexts/OrderingContext/index.js +7 -7
  159. package/cypress/fixtures/example.json +4 -4
  160. package/cypress/integration/naked/BusinessProductsCategories.spec.js +9 -9
  161. package/cypress/integration/naked/PhoneAutocomplete.spec.js +22 -22
  162. package/cypress/integration/naked/activeOrders.spec.js +15 -15
  163. package/cypress/integration/naked/addressDetails.spec.js +10 -10
  164. package/cypress/integration/naked/appleLogin.spec.js +14 -14
  165. package/cypress/integration/naked/businessBasicInformation.spec.js +14 -14
  166. package/cypress/integration/naked/businessController.spec.js +9 -9
  167. package/cypress/integration/naked/businessInformation.spec.js +19 -19
  168. package/cypress/integration/naked/businessProductsSearch.spec.js +9 -9
  169. package/cypress/integration/naked/businessReviews.spec.js +16 -16
  170. package/cypress/integration/naked/businessSortControl.spec.js +9 -9
  171. package/cypress/integration/naked/businessTypeFilter.spec.js +10 -10
  172. package/cypress/integration/naked/businessesMap.spec.js +13 -13
  173. package/cypress/integration/naked/cms.spec.js +9 -9
  174. package/cypress/integration/naked/config.spec.js +34 -34
  175. package/cypress/integration/naked/driverTips.spec.js +10 -10
  176. package/cypress/integration/naked/events.spec.js +13 -13
  177. package/cypress/integration/naked/facebookLogin.spec.js +13 -13
  178. package/cypress/integration/naked/floatingButton.spec.js +13 -13
  179. package/cypress/integration/naked/forgotPassword.spec.js +20 -20
  180. package/cypress/integration/naked/googleLogin.spec.js +11 -11
  181. package/cypress/integration/naked/languageExamples.spec.js +25 -25
  182. package/cypress/integration/naked/languageSelector.spec.js +10 -10
  183. package/cypress/integration/naked/login.spec.js +38 -38
  184. package/cypress/integration/naked/logout.spec.js +15 -15
  185. package/cypress/integration/naked/mainSearch.spec.js +9 -9
  186. package/cypress/integration/naked/menuControl.spec.js +9 -9
  187. package/cypress/integration/naked/messages.spec.js +25 -25
  188. package/cypress/integration/naked/momentOption.spec.js +10 -10
  189. package/cypress/integration/naked/myOrders.spec.js +11 -11
  190. package/cypress/integration/naked/myOrdersList.spec.js +9 -9
  191. package/cypress/integration/naked/orderContextAdvanced.spec.js +23 -23
  192. package/cypress/integration/naked/orderDetails.spec.js +11 -11
  193. package/cypress/integration/naked/paymentOptionCash.spec.js +21 -21
  194. package/cypress/integration/naked/paymentOptionStripe.spec.js +11 -11
  195. package/cypress/integration/naked/paymentOptionStripeDirect.spec.js +11 -11
  196. package/cypress/integration/naked/paymentOptions.spec.js +9 -9
  197. package/cypress/integration/naked/popupExample.spec.js +17 -17
  198. package/cypress/integration/naked/productImages.spec.js +11 -11
  199. package/cypress/integration/naked/productOptionExample.spec.js +21 -21
  200. package/cypress/integration/naked/productShare.spec.js +9 -9
  201. package/cypress/integration/naked/productsList.spec.js +9 -9
  202. package/cypress/integration/naked/resetPassword.spec.js +11 -11
  203. package/cypress/integration/naked/reviewOrders.spec.js +13 -13
  204. package/cypress/integration/naked/searchOptions.spec.js +18 -18
  205. package/cypress/integration/naked/signup.spec.js +31 -31
  206. package/cypress/integration/naked/upselling.spec.js +13 -13
  207. package/cypress/integration/naked/userDetails.spec.js +12 -12
  208. package/cypress/plugins/index.js +21 -21
  209. package/cypress/support/commands.js +35 -35
  210. package/cypress/support/index.js +20 -20
  211. package/cypress.json +12 -12
  212. package/example/App.js +263 -263
  213. package/example/components/ActiveOrdersUI/index.js +72 -72
  214. package/example/components/AddressDetailsUI/index.js +101 -101
  215. package/example/components/AddressFormUI/index.js +161 -161
  216. package/example/components/AddressListUI/index.js +33 -33
  217. package/example/components/AlertPopup/index.js +10 -10
  218. package/example/components/AlertUI/index.js +49 -49
  219. package/example/components/AlertUI/style.css +5 -5
  220. package/example/components/AppleLoginUI/index.js +40 -40
  221. package/example/components/BaseComponentUI/index.js +34 -34
  222. package/example/components/BusinessBasicInformationUI/index.js +118 -118
  223. package/example/components/BusinessControllerUI/index.js +89 -89
  224. package/example/components/BusinessInformationUI/BusinessOptionUI/index.js +83 -83
  225. package/example/components/BusinessInformationUI/index.js +83 -83
  226. package/example/components/BusinessProductsCategoriesUI/index.js +42 -42
  227. package/example/components/BusinessProductsSearchUI/index.js +38 -38
  228. package/example/components/BusinessReviewsUI/index.js +77 -77
  229. package/example/components/BusinessSortControlUI/index.js +47 -47
  230. package/example/components/BusinessTypeFilterUI/index.js +53 -53
  231. package/example/components/BusinessesMapUI/index.js +57 -57
  232. package/example/components/CartUI/index.js +154 -154
  233. package/example/components/ChangeView/index.js +19 -19
  234. package/example/components/CheckoutUI/index.js +206 -206
  235. package/example/components/CmsContentUI/index.js +52 -52
  236. package/example/components/ConfigsExample/index.js +118 -118
  237. package/example/components/CouponControlUI/index.js +63 -63
  238. package/example/components/DriverTipsUI/index.js +58 -58
  239. package/example/components/FacebookLoginButtonUI/index.js +48 -48
  240. package/example/components/FloatingButtonUI/index.js +145 -145
  241. package/example/components/ForgotPasswordFormUI/index.js +93 -93
  242. package/example/components/GoogleLoginUI/index.js +30 -30
  243. package/example/components/GpsButtonUI/index.js +22 -22
  244. package/example/components/Header/index.js +18 -18
  245. package/example/components/LanguageSelectorUI/index.js +57 -57
  246. package/example/components/LanguagesExample/index.js +51 -51
  247. package/example/components/LoginFormUI/index.js +159 -159
  248. package/example/components/LogoutButtonUI/index.js +21 -21
  249. package/example/components/MainSearchUI/index.js +131 -131
  250. package/example/components/MenuControlUI/index.js +103 -103
  251. package/example/components/MessagesUI/index.js +162 -162
  252. package/example/components/ModalUI/index.js +36 -36
  253. package/example/components/ModalUI/style.css +5 -5
  254. package/example/components/MomentOptionUI/index.js +68 -68
  255. package/example/components/MyOrdersListUI/index.js +51 -51
  256. package/example/components/MyOrdersUI/index.js +52 -52
  257. package/example/components/OrderChangeUI/index.js +54 -54
  258. package/example/components/OrderDetailsUI/index.js +174 -174
  259. package/example/components/OrderReviewUI/index.js +125 -125
  260. package/example/components/OrderTypeControlUI/index.js +32 -32
  261. package/example/components/PaymentOptionCashUI/index.js +60 -60
  262. package/example/components/PaymentOptionPaypalUI/index.js +50 -50
  263. package/example/components/PaymentOptionStripeDirectUI/index.js +89 -89
  264. package/example/components/PaymentOptionStripeRedirectUI/index.js +97 -97
  265. package/example/components/PaymentOptionStripeUI/index.js +129 -129
  266. package/example/components/PaymentOptionsUI/index.js +169 -169
  267. package/example/components/PhoneAutocompleteUI/index.js +67 -67
  268. package/example/components/PhoneAutocompleteUI/styles.css +49 -49
  269. package/example/components/ProductComponentUI/index.js +113 -113
  270. package/example/components/ProductFormUI/index.js +131 -131
  271. package/example/components/ProductImagesUI/index.js +82 -82
  272. package/example/components/ProductIngredientUI/index.js +21 -21
  273. package/example/components/ProductOptionSuboptionUI/index.js +65 -65
  274. package/example/components/ProductOptionUI/index.js +31 -31
  275. package/example/components/ProductShareUI/index.js +48 -48
  276. package/example/components/ProductsListUI/index.js +108 -108
  277. package/example/components/ProductsListingUI/index.js +42 -42
  278. package/example/components/ResetPasswordUI/index.js +121 -121
  279. package/example/components/SearchOptionsUI/index.js +82 -82
  280. package/example/components/SignupFormUI/index.js +117 -117
  281. package/example/components/SingleBusinessCardUI/index.js +82 -82
  282. package/example/components/SingleOrderCardUI/index.js +52 -52
  283. package/example/components/SingleProductCardUI/index.js +47 -47
  284. package/example/components/StripeElementsFormUI/CardFormUI/index.js +51 -51
  285. package/example/components/StripeElementsFormUI/CardFormUI/style.css +118 -118
  286. package/example/components/StripeElementsFormUI/index.js +38 -38
  287. package/example/components/StripeRedirectFormUI/index.js +99 -99
  288. package/example/components/TestComponent/index.js +5 -5
  289. package/example/components/UpsellingPageUI/index.js +26 -26
  290. package/example/components/UserDetailsUI/index.js +94 -94
  291. package/example/components/UserProfileUI/index.js +156 -156
  292. package/example/views/ActiveOrders/index.js +86 -86
  293. package/example/views/AddressDetailsExample/index.js +57 -57
  294. package/example/views/AppleLoginExample/index.js +51 -51
  295. package/example/views/BaseComponentExample/index.js +35 -35
  296. package/example/views/BusinessBasicInformationExample/index.js +43 -43
  297. package/example/views/BusinessControllerExample/index.js +55 -55
  298. package/example/views/BusinessInformationExample/index.js +68 -68
  299. package/example/views/BusinessProductsCategoriesExample/index.js +50 -50
  300. package/example/views/BusinessProductsSearchExample/index.js +39 -39
  301. package/example/views/BusinessReviewsExample/index.js +43 -43
  302. package/example/views/BusinessSortControlExample/index.js +53 -53
  303. package/example/views/BusinessTypeFilterExample/index.js +53 -53
  304. package/example/views/BusinessesMapExample/index.js +57 -57
  305. package/example/views/CheckoutExample/index.js +143 -143
  306. package/example/views/CmsContentExample/index.js +44 -44
  307. package/example/views/DriverTipsExample/index.js +47 -47
  308. package/example/views/EventsExample/index.js +26 -26
  309. package/example/views/FacebookLogin/index.js +63 -63
  310. package/example/views/FloatingButtonExample/index.js +47 -47
  311. package/example/views/ForgotPassword/index.js +77 -77
  312. package/example/views/GoogleLoginExample/index.js +85 -85
  313. package/example/views/Home/index.js +200 -200
  314. package/example/views/LanguageSelectorExample/index.js +55 -55
  315. package/example/views/Login/index.js +84 -84
  316. package/example/views/MainSearchExample/index.js +43 -43
  317. package/example/views/MenuControlExample/index.js +68 -68
  318. package/example/views/MessagesExample/index.js +58 -58
  319. package/example/views/MomentOptionExample/index.js +52 -52
  320. package/example/views/MyOrdersExample/index.js +35 -35
  321. package/example/views/MyOrdersListExample/index.js +50 -50
  322. package/example/views/OrderChangeExample/index.js +46 -46
  323. package/example/views/OrderContextExample/index.js +139 -139
  324. package/example/views/OrderDetailsExample/index.js +50 -50
  325. package/example/views/OrderReviewExample/index.js +64 -64
  326. package/example/views/PaymentOptionCashExample/index.js +51 -51
  327. package/example/views/PaymentOptionPaypalExample/index.js +71 -71
  328. package/example/views/PaymentOptionStripeDirectExample/index.js +43 -43
  329. package/example/views/PaymentOptionStripeExample/index.js +47 -47
  330. package/example/views/PaymentOptionStripeRedirectExample/index.js +56 -56
  331. package/example/views/PaymentOptionsExample/index.js +47 -47
  332. package/example/views/PhoneAutocompleteExample/index.js +34 -34
  333. package/example/views/PlacesExample/index.js +94 -94
  334. package/example/views/PopupExample/index.js +78 -78
  335. package/example/views/PopupExample/style.css +18 -18
  336. package/example/views/ProductDetail/index.js +323 -323
  337. package/example/views/ProductImagesExample/index.js +43 -43
  338. package/example/views/ProductOptionExample/index.js +88 -88
  339. package/example/views/ProductShareExample/index.js +51 -51
  340. package/example/views/ProductsListExample/index.js +77 -77
  341. package/example/views/ProductsListingExample/index.js +47 -47
  342. package/example/views/ResetPasswordExample/index.js +60 -60
  343. package/example/views/SearchOptionsExample/index.js +42 -42
  344. package/example/views/SessionManager/index.js +122 -122
  345. package/example/views/Signup/index.js +64 -64
  346. package/example/views/UpsellingPageExample/index.js +35 -35
  347. package/example/views/UserDetailsExample/index.js +69 -69
  348. package/example/views/UserProfile/index.js +73 -73
  349. package/index-example.js +23 -23
  350. package/index.html +13 -13
  351. package/native/index.js +257 -257
  352. package/native/src/NativeStrategy/index.js +20 -20
  353. package/native/src/contexts/OrderingContext/index.js +85 -85
  354. package/package.json +92 -92
  355. package/src/components/AddressDetails/index.js +149 -149
  356. package/src/components/AddressForm/index.js +380 -380
  357. package/src/components/AddressList/index.js +254 -254
  358. package/src/components/Analitycs/index.js +119 -119
  359. package/src/components/AnalyticsSegment/index.js +145 -145
  360. package/src/components/AppleLogin/index.js +164 -164
  361. package/src/components/BaseComponent/index.js +52 -52
  362. package/src/components/BusinessAndProductList/index.js +1005 -1005
  363. package/src/components/BusinessBasicInformation/index.js +119 -119
  364. package/src/components/BusinessController/index.js +351 -351
  365. package/src/components/BusinessInformation/BusinessOption/index.js +86 -86
  366. package/src/components/BusinessInformation/index.js +93 -93
  367. package/src/components/BusinessList/index.js +670 -670
  368. package/src/components/BusinessMenuListing/index.js +99 -99
  369. package/src/components/BusinessProductsCategories/index.js +60 -60
  370. package/src/components/BusinessProductsSearch/index.js +54 -54
  371. package/src/components/BusinessReviews/index.js +187 -187
  372. package/src/components/BusinessSearchList/index.js +364 -364
  373. package/src/components/BusinessSortControl/index.js +100 -100
  374. package/src/components/BusinessTypeFilter/index.js +142 -142
  375. package/src/components/BusinessesMap/index.js +110 -110
  376. package/src/components/Cart/index.js +211 -211
  377. package/src/components/CartStoresListing/index.js +157 -157
  378. package/src/components/Checkout/index.js +652 -652
  379. package/src/components/CmsContent/index.js +97 -97
  380. package/src/components/Contacts/index.js +512 -512
  381. package/src/components/CouponControl/index.js +171 -171
  382. package/src/components/DragAndDrop/index.js +41 -41
  383. package/src/components/DriverList/index.js +112 -112
  384. package/src/components/DriverTips/index.js +141 -141
  385. package/src/components/Emitter/index.js +36 -36
  386. package/src/components/ExamineClick/index.js +40 -40
  387. package/src/components/FacebookLoginButton/index.js +214 -214
  388. package/src/components/FacebookPixel/index.js +148 -148
  389. package/src/components/FavoriteList/index.js +278 -278
  390. package/src/components/FirebaseGoogleLoginButton/index.js +93 -93
  391. package/src/components/FloatingButton/index.js +70 -70
  392. package/src/components/ForgotPasswordForm/index.js +180 -180
  393. package/src/components/GiftCard/GiftCardOrdersList/index.js +155 -155
  394. package/src/components/GiftCard/PurchaseGiftCard/index.js +127 -127
  395. package/src/components/GiftCard/RedeemGiftCard/index.js +77 -77
  396. package/src/components/GiftCard/SendGiftCard/index.js +83 -83
  397. package/src/components/GoogleAutocompleteInput/index.js +154 -154
  398. package/src/components/GoogleIdentity/index.js +144 -144
  399. package/src/components/GoogleLoginButton/index.js +276 -276
  400. package/src/components/GoogleMaps/index.js +523 -523
  401. package/src/components/GpsButton/index.js +154 -154
  402. package/src/components/LanguageSelector/index.js +163 -163
  403. package/src/components/LoginForm/index.js +531 -531
  404. package/src/components/LogoutAction/index.js +211 -211
  405. package/src/components/MainSearch/index.js +149 -149
  406. package/src/components/MapView/index.js +116 -116
  407. package/src/components/MenuControl/index.js +238 -238
  408. package/src/components/Messages/index.js +166 -166
  409. package/src/components/MomentOption/index.js +322 -322
  410. package/src/components/MultiCartCreate/index.js +70 -70
  411. package/src/components/MultiCartsPaymethodsAndWallets/index.js +201 -201
  412. package/src/components/MultiCheckout/index.js +378 -378
  413. package/src/components/MultiOrdersDetails/index.js +109 -109
  414. package/src/components/MyOrders/index.js +150 -150
  415. package/src/components/MyOrdersList/index.js +104 -104
  416. package/src/components/NewOrderNotification/index.js +30 -30
  417. package/src/components/OrderChange/index.js +128 -128
  418. package/src/components/OrderDetails/index.js +684 -684
  419. package/src/components/OrderList/index.js +814 -814
  420. package/src/components/OrderListGroups/index.js +1256 -1256
  421. package/src/components/OrderReview/index.js +180 -180
  422. package/src/components/OrderTypeControl/index.js +75 -75
  423. package/src/components/OrderVerticalList/index.js +422 -422
  424. package/src/components/OrdersControlFilters/index.js +75 -75
  425. package/src/components/OrdersDashboardComponents/Appointments/index.js +72 -72
  426. package/src/components/OrdersDashboardComponents/BusinessProductsListing/index.js +629 -629
  427. package/src/components/OrdersDashboardComponents/CheckPassword/index.js +177 -177
  428. package/src/components/OrdersDashboardComponents/CityList/index.js +98 -98
  429. package/src/components/OrdersDashboardComponents/CountryList/index.js +162 -162
  430. package/src/components/OrdersDashboardComponents/CustomOrderDetails/index.js +238 -238
  431. package/src/components/OrdersDashboardComponents/DashboardBusinessList/index.js +617 -617
  432. package/src/components/OrdersDashboardComponents/DashboardOrdersList/index.js +943 -943
  433. package/src/components/OrdersDashboardComponents/DriversList/index.js +448 -448
  434. package/src/components/OrdersDashboardComponents/ExportCSV/index.js +192 -192
  435. package/src/components/OrdersDashboardComponents/GiftCardsList/index.js +189 -189
  436. package/src/components/OrdersDashboardComponents/GoogleMapsApiKeySetting/index.js +77 -77
  437. package/src/components/OrdersDashboardComponents/LogisticInformation/index.js +97 -97
  438. package/src/components/OrdersDashboardComponents/Logistics/index.js +174 -174
  439. package/src/components/OrdersDashboardComponents/Messages/index.js +384 -384
  440. package/src/components/OrdersDashboardComponents/MetaFields/index.js +186 -186
  441. package/src/components/OrdersDashboardComponents/OrderDetails/index.js +404 -404
  442. package/src/components/OrdersDashboardComponents/OrderNotification/index.js +70 -70
  443. package/src/components/OrdersDashboardComponents/OrdersFilter/index.js +362 -362
  444. package/src/components/OrdersDashboardComponents/OrdersManage/index.js +873 -873
  445. package/src/components/OrdersDashboardComponents/PointsWalletLevels/index.js +123 -123
  446. package/src/components/OrdersDashboardComponents/ReviewCustomer/index.js +113 -113
  447. package/src/components/OrdersDashboardComponents/Schedule/index.js +315 -315
  448. package/src/components/OrdersDashboardComponents/SettingsList/index.js +298 -298
  449. package/src/components/OrdersDashboardComponents/UserFormDetails/index.js +463 -463
  450. package/src/components/OrdersDashboardComponents/UsersList/index.js +944 -944
  451. package/src/components/OrdersDashboardComponents/WebsocketStatus/index.js +77 -77
  452. package/src/components/OrdersDashboardComponents/index.js +57 -57
  453. package/src/components/PageBanner/index.js +107 -107
  454. package/src/components/PaymentOptionCash/index.js +74 -74
  455. package/src/components/PaymentOptionPaypal/index.js +146 -146
  456. package/src/components/PaymentOptionSquare/index.js +336 -336
  457. package/src/components/PaymentOptionStripe/index.js +289 -289
  458. package/src/components/PaymentOptionStripeDirect/index.js +116 -116
  459. package/src/components/PaymentOptionStripeLink/index.js +101 -101
  460. package/src/components/PaymentOptionStripeRedirect/StripeRedirectForm/index.js +71 -71
  461. package/src/components/PaymentOptionStripeRedirect/index.js +122 -122
  462. package/src/components/PaymentOptionWallet/index.js +185 -185
  463. package/src/components/PaymentOptions/index.js +263 -263
  464. package/src/components/PaymethodList/index.js +119 -119
  465. package/src/components/PhoneAutocomplete/index.js +318 -318
  466. package/src/components/PlaceSpot/index.js +183 -183
  467. package/src/components/Popup/index.js +169 -169
  468. package/src/components/ProductComponent/index.js +269 -269
  469. package/src/components/ProductForm/index.js +1149 -1119
  470. package/src/components/ProductImages/index.js +64 -64
  471. package/src/components/ProductIngredient/index.js +72 -72
  472. package/src/components/ProductItemAccordion/index.js +72 -72
  473. package/src/components/ProductOption/index.js +42 -42
  474. package/src/components/ProductOptionSuboption/index.js +225 -225
  475. package/src/components/ProductShare/index.js +97 -97
  476. package/src/components/ProductsList/index.js +74 -74
  477. package/src/components/ProductsListing/index.js +166 -166
  478. package/src/components/ProfessionalInfo/index.js +156 -156
  479. package/src/components/PromotionsController/index.js +123 -123
  480. package/src/components/QueryLoginSpoonity/index.js +159 -159
  481. package/src/components/ReCaptcha/index.js +53 -53
  482. package/src/components/ResetPassword/index.js +111 -111
  483. package/src/components/ReviewCustomer/index.js +117 -117
  484. package/src/components/ReviewDriver/index.js +157 -157
  485. package/src/components/ReviewProduct/index.js +162 -162
  486. package/src/components/SearchOptions/index.js +69 -69
  487. package/src/components/Sessions/index.js +217 -217
  488. package/src/components/SignupForm/index.js +557 -557
  489. package/src/components/SingleBusinessCard/index.js +80 -80
  490. package/src/components/SingleOrderCard/index.js +160 -160
  491. package/src/components/SingleProductCard/index.js +130 -130
  492. package/src/components/SingleProfessionalCard/index.js +121 -121
  493. package/src/components/SmartAppBanner/index.js +71 -71
  494. package/src/components/StoreProductList/index.js +303 -303
  495. package/src/components/StripeElementsForm/CardForm/index.js +248 -248
  496. package/src/components/StripeElementsForm/index.js +78 -78
  497. package/src/components/UpsellingPage/index.js +156 -156
  498. package/src/components/UserFormDetails/index.js +742 -742
  499. package/src/components/UserVerification/index.js +246 -246
  500. package/src/components/WalletList/index.js +160 -160
  501. package/src/components/WebsocketStatus/index.js +80 -80
  502. package/src/components/WrapperGoogleMaps/index.js +67 -67
  503. package/src/constants/code-numbers.js +219 -219
  504. package/src/constants/timezones.js +427 -427
  505. package/src/contexts/ApiContext/index.js +59 -59
  506. package/src/contexts/BillingContext/index.js +28 -28
  507. package/src/contexts/BusinessContext/index.js +71 -71
  508. package/src/contexts/ConfigContext/index.js +217 -217
  509. package/src/contexts/CustomerContext/index.js +69 -69
  510. package/src/contexts/EventContext/index.js +31 -31
  511. package/src/contexts/LanguageContext/index.js +144 -144
  512. package/src/contexts/OptimizationLoadContext/index.js +95 -95
  513. package/src/contexts/OrderContext/index.js +1450 -1450
  514. package/src/contexts/OrderingContext/index.js +86 -86
  515. package/src/contexts/OrderingThemeContext/index.js +107 -107
  516. package/src/contexts/ProductContext/index.js +62 -62
  517. package/src/contexts/SessionContext/index.js +172 -172
  518. package/src/contexts/SiteContext/index.js +79 -79
  519. package/src/contexts/ToastContext/index.js +42 -42
  520. package/src/contexts/UtilsContext/index.js +343 -343
  521. package/src/contexts/ValidationsFieldsContext/index.js +65 -65
  522. package/src/contexts/WebsocketContext/index.js +95 -95
  523. package/src/contexts/WebsocketContext/socket.js +92 -92
  524. package/src/index.js +373 -373
  525. package/src/utils/index.js +32 -32
  526. package/src/webStrategy/index.js +18 -18
  527. package/webpack.dev.js +41 -41
  528. package/webpack.prod.js +64 -64
  529. /package/_bundles/{0.ordering-component.5e6b244837705c07824f.js → 0.ordering-component.6cdb5ba8147ea6e69b23.js} +0 -0
  530. /package/_bundles/{1.ordering-component.5e6b244837705c07824f.js → 1.ordering-component.6cdb5ba8147ea6e69b23.js} +0 -0
  531. /package/_bundles/{2.ordering-component.5e6b244837705c07824f.js → 2.ordering-component.6cdb5ba8147ea6e69b23.js} +0 -0
  532. /package/_bundles/{4.ordering-component.5e6b244837705c07824f.js → 4.ordering-component.6cdb5ba8147ea6e69b23.js} +0 -0
  533. /package/_bundles/{5.ordering-component.5e6b244837705c07824f.js → 5.ordering-component.6cdb5ba8147ea6e69b23.js} +0 -0
  534. /package/_bundles/{6.ordering-component.5e6b244837705c07824f.js → 6.ordering-component.6cdb5ba8147ea6e69b23.js} +0 -0
  535. /package/_bundles/{7.ordering-component.5e6b244837705c07824f.js.LICENSE.txt → 7.ordering-component.6cdb5ba8147ea6e69b23.js.LICENSE.txt} +0 -0
  536. /package/_bundles/{8.ordering-component.5e6b244837705c07824f.js → 8.ordering-component.6cdb5ba8147ea6e69b23.js} +0 -0
  537. /package/_bundles/{ordering-component.5e6b244837705c07824f.js.LICENSE.txt → ordering-component.6cdb5ba8147ea6e69b23.js.LICENSE.txt} +0 -0
@@ -1,1119 +1,1149 @@
1
- import React, { useState, useEffect } from 'react'
2
- import PropTypes from 'prop-types'
3
- import moment from 'moment'
4
- import dayjs from 'dayjs'
5
- import utc from 'dayjs/plugin/utc'
6
- import { useOrder } from '../../contexts/OrderContext'
7
- import { useConfig } from '../../contexts/ConfigContext'
8
- import { useApi } from '../../contexts/ApiContext'
9
- import { useEvent } from '../../contexts/EventContext'
10
- import { useSession } from '../../contexts/SessionContext'
11
- import { ToastType, useToast } from '../../contexts/ToastContext'
12
- import { useLanguage } from '../../contexts/LanguageContext'
13
- import { useWebsocket } from '../../contexts/WebsocketContext'
14
-
15
- dayjs.extend(utc)
16
-
17
- export const ProductForm = (props) => {
18
- const {
19
- UIComponent,
20
- useOrderContext,
21
- onSave,
22
- handleCustomSave,
23
- isStarbucks,
24
- isService,
25
- isCartProduct,
26
- productAddedToCartLength,
27
- professionalList,
28
- handleUpdateProducts,
29
- handleUpdateProfessionals,
30
- handleChangeProfessional,
31
- setProductLoading
32
- } = props
33
-
34
- const requestsState = {}
35
-
36
- const [{ user, token }, { login }] = useSession()
37
- const [, { showToast }] = useToast()
38
- const [, t] = useLanguage()
39
-
40
- const [ordering] = useApi()
41
- const socket = useWebsocket()
42
- /**
43
- * Events context
44
- */
45
- const [events] = useEvent()
46
- /**
47
- * Original product state
48
- */
49
- const availableLazyLoad = props.product?.load_type === 'lazy' && props.businessId && props.categoryId && props.productId
50
- const [product, setProduct] = useState({ product: availableLazyLoad ? null : props.product, loading: false, error: null })
51
-
52
- /**
53
- * Product cart state
54
- */
55
- const [productCart, setProductCart] = useState({ ingredients: {}, options: {} })
56
-
57
- /**
58
- * Errors state
59
- */
60
- const [errors, setErrors] = useState({})
61
-
62
- /**
63
- * Suboption by default when there is only one
64
- */
65
- const [defaultSubOptions, setDefaultSubOptions] = useState([])
66
-
67
- /**
68
- * Custom Suboption by default
69
- */
70
- const [customDefaultSubOptions, setCustomDefaultSubOptions] = useState([])
71
-
72
- /**
73
- * preselected and selected suboptions
74
- */
75
- const [selectedSuboptions, setSelectedSuboptions] = useState([])
76
-
77
- /**
78
- * dictionary of respect_to suboptions
79
- */
80
- const [dependsSuboptions, setDependsSuboptions] = useState([])
81
-
82
- const [professionalListState, setProfessionalListState] = useState({ loading: false, professionals: [], error: null })
83
-
84
- /**
85
- * Action status
86
- */
87
- const [actionStatus, setActionStatus] = useState({ loading: false, error: null })
88
-
89
- /**
90
- * pizza type and position
91
- */
92
- const [pizzaState, setPizzaState] = useState({})
93
-
94
- /**
95
- * Edit mode
96
- */
97
- const editMode = typeof props.productCart?.code !== 'undefined'
98
-
99
- /**
100
- * Order context manager
101
- */
102
- const [orderState, { addProduct, updateProduct, addMultiProduct }] = useOrder()
103
-
104
- /**
105
- * Remove to balances in edit mode
106
- */
107
- const removeToBalance = editMode ? props.productCart.quantity : 0
108
-
109
- /**
110
- * Current cart
111
- */
112
- const cart = orderState.carts?.[`businessId:${props.businessId}`]
113
-
114
- /**
115
- * Total products in cart
116
- */
117
- const cartProducts = Object.values(orderState.carts).reduce((products, _cart) => [...products, ..._cart?.products], [])
118
-
119
- /**
120
- * Total the current product in cart
121
- */
122
- const productBalance = cartProducts.reduce((sum, _product) => sum + (product.product && _product.id === product.product.id ? _product.quantity : 0), 0)
123
-
124
- /**
125
- * Total product in cart
126
- */
127
- const totalBalance = (productBalance || 0) - removeToBalance
128
-
129
- /**
130
- * Config context manager
131
- */
132
- const [stateConfig] = useConfig()
133
-
134
- /**
135
- * Max total product in cart by config
136
- */
137
- const maxCartProductConfig = (stateConfig.configs.max_product_amount ? parseInt(stateConfig.configs.max_product_amount) : 100) - totalBalance
138
-
139
- /**
140
- * Max total product in cart by config
141
- */
142
- let maxCartProductInventory = (product.product?.inventoried ? product.product?.quantity : undefined) - totalBalance
143
-
144
- /**
145
- * True if product is sold out
146
- */
147
- const isSoldOut = product.product?.inventoried && product.product?.quantity === 0
148
-
149
- /**
150
- * Fix if maxCartProductInventory is not valid
151
- */
152
- maxCartProductInventory = !isNaN(maxCartProductInventory) ? maxCartProductInventory : maxCartProductConfig
153
-
154
- /**
155
- * Max product quantity
156
- */
157
- const maxProductQuantity = Math.min(maxCartProductConfig, maxCartProductInventory)
158
-
159
- /**
160
- * alsea validation
161
- */
162
- const isAlsea = ['alsea', 'alsea-staging'].includes(ordering.project)
163
-
164
- /**
165
- * alsea custom options
166
- */
167
- const quesoYSalsaOptions = ['queso y salsa', 'queso mozzarella y salsa']
168
-
169
- /**
170
- * Init product cart status
171
- * @param {object} product Product to init product cart status
172
- */
173
- const initProductCart = (product) => {
174
- const ingredients = {}
175
- for (const key in product.ingredients) {
176
- const ingredient = product.ingredients[key]
177
- ingredients[`id:${ingredient.id}`] = {
178
- selected: true
179
- }
180
- }
181
- const quantity = (productAddedToCartLength && product?.maximum_per_order) ? (product?.maximum_per_order - productAddedToCartLength) : props.productCart?.quantity
182
- const newProductCart = {
183
- ...props.productCart,
184
- id: product.id,
185
- price: product.price,
186
- name: product.name,
187
- businessId: props.businessId,
188
- categoryId: product.category_id,
189
- inventoried: product.inventoried,
190
- stock: product.quantity,
191
- ingredients: props.productCart?.ingredients || ingredients,
192
- options: props.productCart?.options || {},
193
- comment: props.productCart?.comment || null,
194
- quantity: quantity || 1,
195
- favorite: product?.favorite
196
- }
197
- newProductCart.unitTotal = getUnitTotal(newProductCart)
198
- newProductCart.total = newProductCart.unitTotal * newProductCart.quantity
199
- setProductCart(newProductCart)
200
- }
201
-
202
- /**
203
- * Get unit total for product cart
204
- * @param {object} productCart Current product status
205
- */
206
- const getUnitTotal = (productCart) => {
207
- let subtotal = 0
208
- for (let i = 0; i < product.product?.extras?.length; i++) {
209
- const extra = product.product?.extras[i]
210
- for (let j = 0; j < extra.options?.length; j++) {
211
- const option = extra.options[j]
212
- for (let k = 0; k < option.suboptions?.length; k++) {
213
- const suboption = option.suboptions[k]
214
- if (productCart.options[`id:${option.id}`]?.suboptions[`id:${suboption.id}`]?.selected) {
215
- const suboptionState = productCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`]
216
- const quantity = option.allow_suboption_quantity ? suboptionState.quantity : 1
217
- const price = option.with_half_option && suboption.half_price && suboptionState.position !== 'whole' ? suboption.half_price : suboption.price
218
- subtotal += price * quantity
219
- }
220
- }
221
- }
222
- }
223
- return product.product?.price + subtotal
224
- }
225
- /**
226
- * Method to add, remove favorite info for user from API
227
- */
228
- const handleFavoriteProduct = async (productFav, isAdd = false) => {
229
- if (!product || !user) return
230
- showToast(ToastType.Info, t('LOADING', 'loading'))
231
- try {
232
- setProduct({ ...product, loading: true, error: null })
233
- const productId = productFav?.id
234
- const changes = { object_id: productId }
235
- const requestOptions = {
236
- method: isAdd ? 'POST' : 'DELETE',
237
- headers: {
238
- 'Content-Type': 'application/json',
239
- Authorization: `Bearer ${token}`,
240
- 'X-App-X': ordering.appId,
241
- 'X-Socket-Id-X': socket?.getId()
242
- },
243
- ...(isAdd && { body: JSON.stringify(changes) })
244
- }
245
- const fetchEndpoint = isAdd
246
- ? `${ordering.root}/users/${user?.id}/favorite_products`
247
- : `${ordering.root}/users/${user.id}/favorite_products/${productId}`
248
- const response = await fetch(fetchEndpoint, requestOptions)
249
- const content = await response.json()
250
- if (!content.error) {
251
- loadProductWithOptions()
252
- handleUpdateProducts && handleUpdateProducts(productId, { favorite: isAdd })
253
- showToast(ToastType.Success, isAdd ? t('FAVORITE_ADDED', 'Favorite added') : t('FAVORITE_REMOVED', 'Favorite removed'))
254
- } else {
255
- setProduct({
256
- ...product,
257
- loading: false,
258
- error: content.result
259
- })
260
- showToast(ToastType.Error, content.result)
261
- }
262
- } catch (error) {
263
- setProduct({
264
- ...product,
265
- loading: false,
266
- error: [error.message]
267
- })
268
- showToast(ToastType.Error, [error.message])
269
- }
270
- }
271
-
272
- const isValidMoment = (date, format) => dayjs.utc(date, format).format(format) === date
273
- /**
274
- * Load product from API
275
- */
276
- const loadProductWithOptions = async () => {
277
- try {
278
- setProduct({ ...product, loading: true })
279
- const source = {}
280
- requestsState.product = source
281
- const parameters = {
282
- version: 'v2',
283
- type: orderState.options?.type || 1
284
- }
285
- if (orderState.options?.moment && isValidMoment(orderState.options?.moment, 'YYYY-MM-DD HH:mm:ss')) {
286
- const moment = dayjs.utc(orderState.options?.moment, 'YYYY-MM-DD HH:mm:ss').local().unix()
287
- parameters.timestamp = moment
288
- }
289
- const { content: { result, error } } = await ordering
290
- .businesses(props.businessId)
291
- .categories(props.categoryId)
292
- .products(props.productId)
293
- .parameters(parameters)
294
- .get({ cancelToken: source })
295
-
296
- if (!error) {
297
- setProduct({
298
- ...product,
299
- loading: false,
300
- product: result
301
- })
302
- return
303
- }
304
- setProduct({
305
- ...product,
306
- loading: false,
307
- error: [result]
308
- })
309
- } catch (err) {
310
- setProduct({
311
- ...product,
312
- loading: false,
313
- error: [err.message]
314
- })
315
- }
316
- }
317
-
318
- /**
319
- * Remove related option by respect_to
320
- * @param {object} cart Current cart
321
- * @param {number} suboptionId Suboption id
322
- */
323
- const removeRelatedOptions = (productCart, suboptionId) => {
324
- product.product.extras.forEach(_extra => {
325
- _extra.options.forEach(_option => {
326
- if (_option.respect_to === suboptionId) {
327
- const suboptions = productCart.options[`id:${_option.id}`]?.suboptions
328
- if (suboptions) {
329
- Object.keys(suboptions).map(suboptionKey => removeRelatedOptions(productCart, parseInt(suboptionKey.split(':')[1])))
330
- }
331
- if (productCart.options[`id:${_option.id}`]) {
332
- productCart.options[`id:${_option.id}`].suboptions = {}
333
- pizzaState[`option:${_option.id}`] = {}
334
- }
335
- }
336
- })
337
- })
338
- }
339
-
340
- /**
341
- * Get changes for ingredients state
342
- * @param {object} state Current ingrediente state
343
- * @param {object} ingredient Current ingredient
344
- */
345
- const handleChangeIngredientState = (state, ingredient) => {
346
- productCart.ingredients[`id:${ingredient.id}`] = state
347
- setProductCart({
348
- ...productCart,
349
- ingredients: productCart.ingredients
350
- })
351
- }
352
-
353
- /**
354
- * Change product state with new suboption state
355
- * @param {object} state New state with changes
356
- * @param {object} suboption Suboption object
357
- * @param {objecrt} option Option object
358
- * @param {object} product Product object
359
- */
360
- const handleChangeSuboptionState = (state, suboption, option) => {
361
- const newProductCart = JSON.parse(JSON.stringify(productCart))
362
- if (!newProductCart.options) {
363
- newProductCart.options = {}
364
- }
365
- if (!newProductCart.options[`id:${option.id}`]) {
366
- newProductCart.options[`id:${option.id}`] = {
367
- id: option.id,
368
- name: option.name,
369
- suboptions: {}
370
- }
371
- }
372
- let newPizzaState = {}
373
-
374
- if (!state.selected) {
375
- delete newProductCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`]
376
- removeRelatedOptions(newProductCart, suboption.id)
377
- newPizzaState = handleVerifyPizzaState(state, suboption, option)
378
- } else {
379
- if (option.min === option.max && option.min === 1) {
380
- const suboptions = newProductCart.options[`id:${option.id}`].suboptions
381
- if (suboptions) {
382
- Object.keys(suboptions).map(suboptionKey => removeRelatedOptions(newProductCart, parseInt(suboptionKey.split(':')[1])))
383
- }
384
- if (newProductCart.options[`id:${option.id}`]) {
385
- newProductCart.options[`id:${option.id}`].suboptions = {}
386
- }
387
- }
388
- newProductCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`] = state
389
- }
390
- let suboptionsArray = []
391
- const _selectedSuboptions = selectedSuboptions
392
- if (state.selected) {
393
- for (const extra of product.product.extras) {
394
- for (const option of extra.options) {
395
- if (Object.keys(newProductCart?.options[`id:${option?.id}`]?.suboptions || {})?.length === 0) {
396
- delete newProductCart?.options[`id:${option?.id}`]
397
- }
398
- }
399
- }
400
- if (newProductCart?.options) {
401
- for (const extra of product.product.extras) {
402
- for (const option of extra.options) {
403
- for (const suboption of option.suboptions) {
404
- if (newProductCart?.options[`id:${option?.id}`]) {
405
- if (newProductCart?.options[`id:${option?.id}`]?.suboptions[`id:${suboption?.id}`]) {
406
- _selectedSuboptions[`suboption:${suboption.id}`] = true
407
- } else {
408
- _selectedSuboptions[`suboption:${suboption.id}`] = false
409
- }
410
- } else {
411
- _selectedSuboptions[`suboption:${suboption.id}`] = suboption?.preselected || (option?.max === 1 && option?.min === 1 && option?.suboptions?.length === 1)
412
- }
413
- }
414
- }
415
- }
416
- }
417
- const preselectedOptions = []
418
- const preselectedSuboptions = []
419
- for (const extra of product.product.extras) {
420
- for (const option of extra.options) {
421
- for (const suboption of option.suboptions) {
422
- if (checkSuboptionsSelected(suboption?.id, _selectedSuboptions, dependsSuboptions)) {
423
- preselectedOptions.push(option)
424
- preselectedSuboptions.push(suboption)
425
- }
426
- }
427
- }
428
- }
429
-
430
- const states = preselectedSuboptions.map((suboption, i) => {
431
- const cartSuboption = newProductCart?.options[`id:${preselectedOptions[i]?.id}`]?.suboptions[`id:${suboption?.id}`] || suboption
432
- const price = preselectedOptions[i]?.with_half_option && cartSuboption?.half_price && cartSuboption?.position !== 'whole'
433
- ? cartSuboption.half_price
434
- : cartSuboption.price
435
-
436
- return {
437
- id: cartSuboption.id,
438
- name: cartSuboption.name,
439
- position: state?.id === cartSuboption?.id ? state?.position : cartSuboption.position || 'whole',
440
- price: state?.id === cartSuboption?.id ? state.price : price,
441
- quantity: state?.id === cartSuboption?.id
442
- ? state.quantity
443
- : quesoYSalsaOptions.includes(preselectedOptions[i]?.name?.toLowerCase()) && isAlsea
444
- ? cartSuboption?.quantity ?? 1
445
- : cartSuboption?.quantity || 1,
446
- selected: true,
447
- total: state?.id === cartSuboption?.id ? state.total : price
448
- }
449
- })
450
- preselectedOptions.map((option, i) => {
451
- const defaultSuboption = {
452
- option: option,
453
- suboption: preselectedSuboptions[i],
454
- state: states[i]
455
- }
456
- suboptionsArray = [...suboptionsArray, defaultSuboption]
457
- })
458
- newPizzaState = handleVerifyPizzaState(state, suboption, option, preselectedOptions, preselectedSuboptions, states)
459
- }
460
-
461
- let newBalance = Object.keys(newProductCart.options[`id:${option.id}`].suboptions).length
462
- if (option.limit_suboptions_by_max) {
463
- newBalance = Object.values(newProductCart.options[`id:${option.id}`].suboptions).reduce((count, suboption) => {
464
- return count + suboption.quantity
465
- }, 0)
466
- }
467
- const hasPreselectedFlow = suboptionsArray.filter(state => state?.suboption?.preselected)
468
- if (newBalance <= option.max || (newPizzaState?.[`option:${option?.id}`]?.value <= option.max && option?.with_half_option)) {
469
- newProductCart.options[`id:${option.id}`].balance = newBalance
470
- newProductCart.unitTotal = getUnitTotal(newProductCart)
471
- newProductCart.total = newProductCart.unitTotal * newProductCart.quantity
472
- if (state.selected && hasPreselectedFlow?.length > 0) {
473
- handleChangeSuboptionDefault(suboptionsArray, newPizzaState)
474
- setSelectedSuboptions(_selectedSuboptions)
475
- } else {
476
- setProductCart(newProductCart)
477
- }
478
- }
479
- }
480
-
481
- const handleChangeSuboptionDefault = (defaultOptions, newPizzaState) => {
482
- const newProductCart = JSON.parse(JSON.stringify(productCart))
483
- if (!newProductCart.options) {
484
- newProductCart.options = {}
485
- }
486
- defaultOptions.map(({ option, state, suboption }) => {
487
- if (!newProductCart.options[`id:${option.id}`]) {
488
- newProductCart.options[`id:${option.id}`] = {
489
- id: option.id,
490
- name: option.name,
491
- suboptions: {}
492
- }
493
- }
494
- if (!state?.selected) {
495
- delete newProductCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`]
496
- removeRelatedOptions(newProductCart, suboption.id)
497
- } else {
498
- if ((option.min === option.max) && option.min === 1) {
499
- const suboptions = newProductCart.options[`id:${option.id}`].suboptions
500
- if (suboptions) {
501
- Object.keys(suboptions).map(suboptionKey => removeRelatedOptions(newProductCart, parseInt(suboptionKey.split(':')[1])))
502
- }
503
- if (newProductCart.options[`id:${option.id}`]) {
504
- newProductCart.options[`id:${option.id}`].suboptions = {}
505
- }
506
- }
507
- newProductCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`] = state
508
- }
509
- let newBalance = Object.keys(newProductCart.options[`id:${option.id}`].suboptions).length
510
- if (option.limit_suboptions_by_max) {
511
- newBalance = Object.values(newProductCart.options[`id:${option.id}`].suboptions).reduce((count, suboption) => {
512
- return count + suboption.quantity
513
- }, 0)
514
- }
515
-
516
- if (newBalance <= option.max || (newPizzaState?.[`option:${option.id}`]?.value <= option.max && option?.with_half_option)) {
517
- newProductCart.options[`id:${option.id}`].balance = newBalance
518
- newProductCart.unitTotal = getUnitTotal(newProductCart)
519
- newProductCart.total = newProductCart.unitTotal * newProductCart.quantity
520
- }
521
- })
522
- setProductCart(newProductCart)
523
- }
524
-
525
- /**
526
- * Change product state with new comment state
527
- * @param {object} e Product comment
528
- */
529
- const handleChangeCommentState = (e) => {
530
- const comment = e.target.value ?? ''
531
- productCart.comment = comment.trim()
532
- setProductCart({
533
- ...productCart,
534
- comment: comment.trim()
535
- })
536
- }
537
-
538
- /**
539
- * Check options to get errors
540
- */
541
- const checkErrors = () => {
542
- const errors = {}
543
- if (!product?.product) {
544
- return errors
545
- }
546
- product?.product?.extras?.forEach(extra => {
547
- extra?.options?.map(option => {
548
- const suboptions = productCart.options[`id:${option.id}`]?.suboptions
549
- const quantity = suboptions
550
- ? option?.with_half_option
551
- ? pizzaState?.[`option:${option?.id}`]?.value
552
- : (option.limit_suboptions_by_max
553
- ? Object.values(suboptions).reduce((count, suboption) => {
554
- return count + suboption.quantity
555
- }, 0)
556
- : Object.keys(suboptions)?.length)
557
- : 0
558
- let evaluateRespectTo = false
559
- if (option.respect_to && productCart.options) {
560
- const options = productCart?.options
561
- for (const key in options) {
562
- const _option = options[key]
563
- if (_option.suboptions[`id:${option.respect_to}`]?.selected) {
564
- evaluateRespectTo = true
565
- break
566
- }
567
- }
568
- }
569
- const evaluate = option.respect_to ? evaluateRespectTo : true
570
- if (option?.suboptions?.length > 0 && evaluate) {
571
- if (option.min > quantity) {
572
- errors[`id:${option.id}`] = true
573
- } else if (option.max < quantity && (option?.with_half_option && isAlsea && (option.max + 0.5 < quantity))) {
574
- errors[`id:${option.id}`] = true
575
- }
576
- }
577
- })
578
- })
579
- setErrors(errors)
580
- return errors
581
- }
582
-
583
- /**
584
- * Handle when click on save product
585
- */
586
- const handleSave = async (values) => {
587
- try {
588
- setProductLoading && setProductLoading(true)
589
- if (handleCustomSave) {
590
- handleCustomSave && handleCustomSave()
591
- }
592
- const errors = checkErrors()
593
- const isMultiProduct = JSON.parse(product?.product?.meta || '{}')?.external_type === 'coupon'
594
- const hasAlreadyCoupon = cart?.metafields?.find?.(meta => meta?.key === 'pulse_coupons')?.value && isMultiProduct
595
-
596
- if ((Object.keys(errors).length === 0 || isService) && !hasAlreadyCoupon) {
597
- let successful = true
598
- if (useOrderContext) {
599
- successful = false
600
- const changes = cart || { business_id: props.businessId }
601
- const currentProduct = !isService
602
- ? { ...productCart }
603
- : {
604
- ...productCart,
605
- professional_id: values?.professional?.id,
606
- service_start: values?.serviceTime ?? orderState.options?.moment
607
- }
608
- onSave(productCart, !props.productCart?.code)
609
- if (!props.productCart?.code) {
610
- successful =
611
- isMultiProduct
612
- ? await addMultiProduct(currentProduct, changes, false)
613
- : await addProduct(currentProduct, changes, false)
614
- } else {
615
- successful = await updateProduct(currentProduct, changes, false)
616
- if (successful) {
617
- events.emit('product_edited', currentProduct)
618
- }
619
- }
620
- }
621
- if (successful) {
622
- if (isService) {
623
- const updatedProfessional = JSON.parse(JSON.stringify(values?.professional))
624
- const duration = product?.product?.duration
625
- updatedProfessional.busy_times.push({
626
- start: values?.serviceTime,
627
- end: moment(values?.serviceTime).add(duration, 'minutes').format('YYYY-MM-DD HH:mm:ss'),
628
- duration
629
- })
630
- handleUpdateProfessionals && handleUpdateProfessionals(updatedProfessional)
631
- handleChangeProfessional && handleChangeProfessional(updatedProfessional)
632
- }
633
- } else {
634
- showToast(
635
- ToastType.Error,
636
- !props.productCart?.code ? t('FAILED_TO_ADD_PRODUCT', 'Failed to add product') : t('FAILED_TO_UPDATE_PRODUCT', 'Failed to update product'),
637
- 5000
638
- )
639
- }
640
- }
641
- if (hasAlreadyCoupon) {
642
- showToast(
643
- ToastType.Error,
644
- t('COUPON_ALREADY_ADDED', 'You have a coupon already added')
645
- )
646
- }
647
- setProductLoading && setProductLoading(false)
648
- } catch (err) {
649
- showToast(
650
- ToastType.Error,
651
- !props.productCart?.code ? t('FAILED_TO_ADD_PRODUCT', 'Failed to add product') : t('FAILED_TO_UPDATE_PRODUCT', 'Failed to update product')
652
- )
653
- setProductLoading && setProductLoading(false)
654
- }
655
- }
656
-
657
- const handleCreateGuestUser = async (values) => {
658
- try {
659
- setActionStatus({ ...actionStatus, loading: true })
660
- const { content: { error, result } } = await ordering.users().save(values)
661
- if (!error) {
662
- setActionStatus({ error: null, loading: false })
663
- login({
664
- user: result,
665
- token: result.session?.access_token
666
- })
667
- } else {
668
- setActionStatus({ error: result, loading: false })
669
- }
670
- } catch (err) {
671
- setActionStatus({ error: err.message, loading: false })
672
- }
673
- }
674
-
675
- const increment = () => {
676
- if (maxProductQuantity <= 0 || productCart.quantity >= maxProductQuantity) {
677
- return
678
- }
679
- productCart.quantity++
680
- productCart.unitTotal = getUnitTotal(productCart)
681
- productCart.total = productCart.unitTotal * productCart.quantity
682
- setProductCart({
683
- ...productCart
684
- })
685
- }
686
-
687
- const decrement = () => {
688
- if (productCart.quantity === 0) {
689
- return
690
- }
691
- productCart.quantity--
692
- productCart.unitTotal = getUnitTotal(productCart)
693
- productCart.total = productCart.unitTotal * productCart.quantity
694
- setProductCart({
695
- ...productCart
696
- })
697
- }
698
-
699
- const handleChangeProductCartQuantity = (quantity) => {
700
- if (maxProductQuantity <= 0 || quantity > maxProductQuantity) {
701
- return
702
- }
703
- productCart.quantity = quantity || 0
704
- productCart.total = productCart.unitTotal * productCart.quantity
705
- setProductCart({
706
- ...productCart
707
- })
708
- }
709
-
710
- /**
711
- * Check if option must show
712
- * @param {object} option Option to check
713
- */
714
- const showOption = (option) => {
715
- let showOption = true
716
- if (option.respect_to) {
717
- showOption = false
718
- if (productCart.options) {
719
- const options = productCart.options
720
- for (const key in options) {
721
- const _option = options[key]
722
- if (_option.suboptions[`id:${option.respect_to}`]?.selected) {
723
- showOption = true
724
- break
725
- }
726
- }
727
- }
728
- }
729
-
730
- if (option?.suboptions?.length === 0) showOption = false
731
-
732
- return showOption
733
- }
734
-
735
- /**
736
- * Load professionals from API
737
- */
738
- const getProfessionalList = async () => {
739
- try {
740
- setProfessionalListState({ ...professionalListState, loading: true })
741
- const { content: { result, error } } = await ordering
742
- .businesses(props.businessId)
743
- .select(['id', 'professionals'])
744
- .get()
745
-
746
- if (!error) {
747
- setProfessionalListState({
748
- ...professionalListState,
749
- loading: false,
750
- professionals: result?.professionals ?? []
751
- })
752
- return
753
- }
754
- setProfessionalListState({
755
- ...professionalListState,
756
- loading: false,
757
- error: [result]
758
- })
759
- } catch (err) {
760
- setProfessionalListState({
761
- ...professionalListState,
762
- loading: false,
763
- error: [err.message]
764
- })
765
- }
766
- }
767
- /**
768
- * function to verify position of pizza ingredients
769
- * @param {object} newProductCart cart updated with suboptions
770
- */
771
- const handleVerifyPizzaState = (state, suboption, option, preselectedOptions, preselectedSuboptions, states) => {
772
- let newPizzaState = {}
773
- if (state?.selected) {
774
- preselectedOptions.map((option, i) => {
775
- if (option?.with_half_option) {
776
- newPizzaState = {
777
- ...newPizzaState,
778
- [`option:${option?.id}`]: {
779
- ...newPizzaState?.[`option:${option?.id}`],
780
- [`suboption:${preselectedSuboptions[i]?.id}`]:
781
- isAlsea
782
- ? (states[i]?.position === 'whole' ? 1 : 0.5) + (states[i].quantity >= 2 ? 0.5 : 0)
783
- : (states[i]?.position === 'whole' ? 1 : 0.5) * states[i].quantity
784
- }
785
- }
786
- const suboptionValue = isAlsea
787
- ? ((states[i]?.position === 'whole' || (option?.max === 1 && option?.min === 1) ? 1 : 0.5) + (states[i].quantity >= 2 ? 0.5 : 0))
788
- : ((states[i]?.position === 'whole' || (option?.max === 1 && option?.min === 1) ? 1 : 0.5) * states[i].quantity)
789
-
790
- const value = suboptionValue + (newPizzaState[`option:${option?.id}`].value || 0)
791
- newPizzaState[`option:${option?.id}`].value = value
792
- }
793
- })
794
- } else {
795
- newPizzaState = {
796
- ...pizzaState,
797
- [`option:${option?.id}`]: {
798
- ...pizzaState[`option:${option?.id}`],
799
- value: 0
800
- }
801
- }
802
- delete newPizzaState?.[`option:${option?.id}`]?.[`suboption:${suboption?.id}`]
803
- const value = Object?.values(newPizzaState?.[`option:${option?.id}`] || {})?.reduce((acc, value) => acc + value, 0)
804
- newPizzaState[`option:${option?.id}`].value = value
805
- }
806
- setPizzaState(newPizzaState)
807
- return newPizzaState
808
- }
809
- /**
810
- * Init product cart when product changed
811
- */
812
- useEffect(() => {
813
- if (product.product) {
814
- initProductCart(product.product)
815
- }
816
- }, [product.product])
817
-
818
- /**
819
- * Check error when product state changed
820
- */
821
- useEffect(() => {
822
- checkErrors()
823
- }, [productCart])
824
-
825
- /**
826
- * Listening product changes
827
- */
828
- useEffect(() => {
829
- if (props?.product?.load_type === 'lazy') return
830
- setProduct({ ...product, product: props.product })
831
- }, [props.product])
832
-
833
- /**
834
- * Check if there is an option required with one suboption
835
- */
836
-
837
- const checkSuboptionsSelected = (suboptionId, _selectedSuboptions, _dependsSuboptions, count = 0) => {
838
- if (count > 100) {
839
- return false
840
- }
841
- if (!_selectedSuboptions[`suboption:${suboptionId}`]) {
842
- return false
843
- }
844
- const respectTo = _dependsSuboptions[`suboption:${suboptionId}`] ?? null
845
- if (respectTo === null) {
846
- return _selectedSuboptions[`suboption:${suboptionId}`]
847
- }
848
- return checkSuboptionsSelected(respectTo, _selectedSuboptions, _dependsSuboptions, count++)
849
- }
850
-
851
- useEffect(() => {
852
- if (!product?.loading && product?.product && product.product?.extras?.length > 0) {
853
- const _selectedSuboptions = {}
854
- const _dependsSuboptions = {}
855
- const preselectedOptions = []
856
- const preselectedSuboptions = []
857
- for (const extra of product?.product?.extras) {
858
- if (extra?.options) {
859
- for (const option of extra?.options) {
860
- for (const suboption of option?.suboptions) {
861
- _selectedSuboptions[`suboption:${suboption.id}`] =
862
- (suboption.preselected ||
863
- (option?.max === 1 && option?.min === 1 && option?.suboptions?.length === 1)) &&
864
- (!editMode || !!props.productCart?.options[`id:${option?.id}`]?.suboptions[`id:${suboption?.id}`])
865
- _dependsSuboptions[`suboption:${suboption.id}`] = option?.conditioned && option?.respect_to !== null ? option?.respect_to : null
866
- }
867
- }
868
- }
869
- }
870
-
871
- if (editMode && props?.productCart) {
872
- Object.values(props?.productCart?.options)?.map(option => Object.values(option?.suboptions)?.map(suboption => {
873
- _selectedSuboptions[`suboption:${suboption.id}`] = true
874
- }))
875
- }
876
-
877
- for (const extra of product?.product?.extras) {
878
- if (extra?.options) {
879
- for (const option of extra?.options) {
880
- for (const suboption of option?.suboptions) {
881
- if (checkSuboptionsSelected(suboption?.id, _selectedSuboptions, _dependsSuboptions)) {
882
- preselectedOptions.push(option)
883
- preselectedSuboptions.push(suboption)
884
- }
885
- }
886
- }
887
- }
888
- }
889
- setSelectedSuboptions(_selectedSuboptions)
890
- setDependsSuboptions(_dependsSuboptions)
891
- if (!preselectedOptions?.length) {
892
- return
893
- }
894
- let states = {}
895
- if (editMode && props?.productCart) {
896
- const cartSuboptions = Object.values(props?.productCart?.options)?.map(option => Object.values(option?.suboptions))?.flat()
897
- states = cartSuboptions.map((suboption, i) => {
898
- const price = preselectedOptions[i]?.with_half_option && suboption?.half_price && suboption?.position !== 'whole'
899
- ? suboption.half_price
900
- : suboption.price
901
- return {
902
- id: suboption.id,
903
- name: suboption.name,
904
- position: suboption.position || 'whole',
905
- price,
906
- quantity: suboption.quantity,
907
- selected: true,
908
- total: price
909
- }
910
- })
911
- } else {
912
- states = preselectedSuboptions.map((suboption, i) => {
913
- const price = preselectedOptions[i]?.with_half_option && suboption?.half_price && suboption?.position !== 'whole'
914
- ? suboption.half_price
915
- : suboption.price
916
-
917
- return {
918
- id: suboption.id,
919
- name: suboption.name,
920
- position: suboption.position || 'whole',
921
- price,
922
- quantity: 1,
923
- selected: true,
924
- total: price
925
- }
926
- })
927
- }
928
-
929
- let suboptionsArray = []
930
- let newPizzaState = {}
931
- preselectedOptions.map((option, i) => {
932
- const defaultSuboption = {
933
- option: option,
934
- suboption: preselectedSuboptions[i],
935
- state: states?.find((state) => state?.id === preselectedSuboptions[i]?.id)
936
- }
937
- suboptionsArray = [...suboptionsArray, defaultSuboption]
938
- if (option?.with_half_option) {
939
- newPizzaState = {
940
- ...newPizzaState,
941
- [`option:${option?.id}`]: {
942
- ...newPizzaState?.[`option:${option?.id}`],
943
- [`suboption:${preselectedSuboptions[i]?.id}`]: isAlsea
944
- ? (states[i]?.position === 'whole' ? 1 : 0.5) + (states[i].quantity >= 2 ? 0.5 : 0)
945
- : (states[i]?.position === 'whole' ? 1 : 0.5) * states[i].quantity
946
- }
947
- }
948
- const suboptionValue = isAlsea
949
- ? ((states[i]?.position === 'whole' || (option?.max === 1 && option?.min === 1) ? 1 : 0.5) + (states[i].quantity >= 2 ? 0.5 : 0))
950
- : ((states[i]?.position === 'whole' || (option?.max === 1 && option?.min === 1) ? 1 : 0.5) * states[i].quantity)
951
-
952
- const value = suboptionValue + (newPizzaState[`option:${option?.id}`].value || 0)
953
- newPizzaState[`option:${option?.id}`].value = value
954
- }
955
- })
956
- setPizzaState(newPizzaState)
957
- setDefaultSubOptions(suboptionsArray)
958
- setCustomDefaultSubOptions(suboptionsArray)
959
- }
960
- }, [JSON.stringify(product.product), product?.loading])
961
-
962
- if (isStarbucks) {
963
- useEffect(() => {
964
- if (product?.product && Object.keys(product?.product).length) {
965
- const options = [].concat(...product.product?.extras?.map(extra => extra?.options?.filter(
966
- option => (
967
- option.name === 'Tamaño' &&
968
- option.suboptions.filter(suboption => suboption.name === 'Grande (16oz - 437ml)').length === 1
969
- )
970
- )))
971
- if (!options?.length) {
972
- return
973
- }
974
- const suboptions = []
975
- .concat(...options.map(option => option.suboptions))
976
- .filter(suboption => suboption.name === 'Grande (16oz - 437ml)')
977
- const states = suboptions.map((suboption, i) => {
978
- const price = options[i].with_half_option && suboption.half_price && suboption?.position !== 'whole'
979
- ? suboption.half_price
980
- : suboption.price
981
-
982
- return {
983
- id: suboption.id,
984
- name: suboption.name,
985
- position: suboption.position || 'whole',
986
- price,
987
- quantity: 1,
988
- selected: true,
989
- total: price
990
- }
991
- })
992
- const defaultOptions = options.map((option, i) => {
993
- return {
994
- option: option,
995
- suboption: suboptions[i],
996
- state: states[i]
997
- }
998
- })
999
- setDefaultSubOptions([...customDefaultSubOptions, ...defaultOptions])
1000
- }
1001
- }, [customDefaultSubOptions])
1002
- }
1003
- /**
1004
- * Check if defaultSubOption has content to set product Cart
1005
- */
1006
- useEffect(() => {
1007
- if (defaultSubOptions?.length) {
1008
- handleChangeSuboptionDefault(defaultSubOptions)
1009
- }
1010
- }, [JSON.stringify(defaultSubOptions)])
1011
-
1012
- /**
1013
- * Load product on component mounted
1014
- */
1015
- useEffect(() => {
1016
- if (!props.product && (!props.businessId || !props.categoryId || !props.productId)) {
1017
- throw new Error('`businessId` && `categoryId` && `productId` are required if `product` was not provided.')
1018
- }
1019
- if ((props.product && props.product?.load_type === 'lazy' && props.businessId && props.categoryId && props.productId) ||
1020
- (!props.product && props.businessId && props.categoryId && props.productId)
1021
- ) {
1022
- loadProductWithOptions()
1023
- }
1024
- return () => {
1025
- if (requestsState.product) {
1026
- requestsState.product.cancel()
1027
- }
1028
- }
1029
- }, [])
1030
-
1031
- useEffect(() => {
1032
- if (!isService) return
1033
-
1034
- if (isCartProduct) {
1035
- getProfessionalList()
1036
- } else {
1037
- setProfessionalListState({
1038
- ...professionalListState,
1039
- professionals: professionalList
1040
- })
1041
- }
1042
- }, [isService, isCartProduct, professionalList])
1043
-
1044
- return (
1045
- <>
1046
- {
1047
- UIComponent && (
1048
- <UIComponent
1049
- {...props}
1050
- productObject={product}
1051
- productCart={productCart}
1052
- errors={errors}
1053
- editMode={editMode}
1054
- isSoldOut={isSoldOut}
1055
- actionStatus={actionStatus}
1056
- maxProductQuantity={maxProductQuantity}
1057
- pizzaState={pizzaState}
1058
- setPizzaState={setPizzaState}
1059
- increment={increment}
1060
- decrement={decrement}
1061
- handleChangeProductCartQuantity={handleChangeProductCartQuantity}
1062
- handleSave={handleSave}
1063
- showOption={showOption}
1064
- handleCreateGuestUser={handleCreateGuestUser}
1065
- handleFavoriteProduct={handleFavoriteProduct}
1066
- handleChangeIngredientState={handleChangeIngredientState}
1067
- handleChangeSuboptionState={handleChangeSuboptionState}
1068
- handleChangeCommentState={handleChangeCommentState}
1069
- professionalListState={professionalListState}
1070
- cart2={props.productCart}
1071
- isAlsea={isAlsea}
1072
- quesoYSalsaOptions={quesoYSalsaOptions}
1073
- />
1074
- )
1075
- }
1076
- </>
1077
- )
1078
- }
1079
-
1080
- ProductForm.propTypes = {
1081
- /**
1082
- * UI Component, this must be containt all graphic elements and use parent props
1083
- */
1084
- UIComponent: PropTypes.elementType,
1085
- /**
1086
- * `businessId`
1087
- */
1088
- businessId: PropTypes.number.isRequired,
1089
- /**
1090
- * `categoryId` is required if `product` prop is not present
1091
- */
1092
- categoryId: PropTypes.number,
1093
- /**
1094
- * `productId` is required if `product` prop is not present
1095
- */
1096
- productId: PropTypes.number,
1097
- /**
1098
- * `product` is required if `businessId`, `categoryId` or `productId` is not present
1099
- */
1100
- product: PropTypes.object,
1101
- /**
1102
- * Product from cart
1103
- */
1104
- productCart: PropTypes.object,
1105
- /**
1106
- * useOrderContext
1107
- */
1108
- useOrderContext: PropTypes.bool,
1109
- /**
1110
- * Function to save event
1111
- */
1112
- onSave: PropTypes.func
1113
- }
1114
-
1115
- ProductForm.defaultProps = {
1116
- productCart: {},
1117
- useOrderContext: true,
1118
- balance: 0
1119
- }
1
+ import React, { useState, useEffect } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import moment from 'moment'
4
+ import dayjs from 'dayjs'
5
+ import utc from 'dayjs/plugin/utc'
6
+ import { useOrder } from '../../contexts/OrderContext'
7
+ import { useConfig } from '../../contexts/ConfigContext'
8
+ import { useApi } from '../../contexts/ApiContext'
9
+ import { useEvent } from '../../contexts/EventContext'
10
+ import { useSession } from '../../contexts/SessionContext'
11
+ import { ToastType, useToast } from '../../contexts/ToastContext'
12
+ import { useLanguage } from '../../contexts/LanguageContext'
13
+ import { useWebsocket } from '../../contexts/WebsocketContext'
14
+
15
+ dayjs.extend(utc)
16
+
17
+ export const ProductForm = (props) => {
18
+ const {
19
+ UIComponent,
20
+ useOrderContext,
21
+ onSave,
22
+ handleCustomSave,
23
+ isStarbucks,
24
+ isService,
25
+ isCartProduct,
26
+ productAddedToCartLength,
27
+ professionalList,
28
+ handleUpdateProducts,
29
+ handleUpdateProfessionals,
30
+ handleChangeProfessional,
31
+ setProductLoading
32
+ } = props
33
+
34
+ const requestsState = {}
35
+
36
+ const [{ user, token }, { login }] = useSession()
37
+ const [, { showToast }] = useToast()
38
+ const [, t] = useLanguage()
39
+
40
+ const [ordering] = useApi()
41
+ const socket = useWebsocket()
42
+ /**
43
+ * Events context
44
+ */
45
+ const [events] = useEvent()
46
+ /**
47
+ * Original product state
48
+ */
49
+ const availableLazyLoad = props.product?.load_type === 'lazy' && props.businessId && props.categoryId && props.productId
50
+ const [product, setProduct] = useState({ product: availableLazyLoad ? null : props.product, loading: false, error: null })
51
+
52
+ /**
53
+ * Product cart state
54
+ */
55
+ const [productCart, setProductCart] = useState({ ingredients: {}, options: {} })
56
+
57
+ /**
58
+ * Errors state
59
+ */
60
+ const [errors, setErrors] = useState({})
61
+
62
+ /**
63
+ * Suboption by default when there is only one
64
+ */
65
+ const [defaultSubOptions, setDefaultSubOptions] = useState([])
66
+
67
+ /**
68
+ * Custom Suboption by default
69
+ */
70
+ const [customDefaultSubOptions, setCustomDefaultSubOptions] = useState([])
71
+
72
+ /**
73
+ * preselected and selected suboptions
74
+ */
75
+ const [selectedSuboptions, setSelectedSuboptions] = useState([])
76
+
77
+ /**
78
+ * dictionary of respect_to suboptions
79
+ */
80
+ const [dependsSuboptions, setDependsSuboptions] = useState([])
81
+
82
+ const [professionalListState, setProfessionalListState] = useState({ loading: false, professionals: [], error: null })
83
+
84
+ /**
85
+ * Action status
86
+ */
87
+ const [actionStatus, setActionStatus] = useState({ loading: false, error: null })
88
+
89
+ /**
90
+ * pizza type and position
91
+ */
92
+ const [pizzaState, setPizzaState] = useState({})
93
+
94
+ /**
95
+ * Edit mode
96
+ */
97
+ const editMode = typeof props.productCart?.code !== 'undefined'
98
+
99
+ /**
100
+ * Order context manager
101
+ */
102
+ const [orderState, { addProduct, updateProduct, addMultiProduct }] = useOrder()
103
+
104
+ /**
105
+ * Remove to balances in edit mode
106
+ */
107
+ const removeToBalance = editMode ? props.productCart.quantity : 0
108
+
109
+ /**
110
+ * Current cart
111
+ */
112
+ const cart = orderState.carts?.[`businessId:${props.businessId}`]
113
+
114
+ /**
115
+ * Total products in cart
116
+ */
117
+ const cartProducts = Object.values(orderState.carts).reduce((products, _cart) => [...products, ..._cart?.products], [])
118
+
119
+ /**
120
+ * Total the current product in cart
121
+ */
122
+ const productBalance = cartProducts.reduce((sum, _product) => sum + (product.product && _product.id === product.product.id ? _product.quantity : 0), 0)
123
+
124
+ /**
125
+ * Total product in cart
126
+ */
127
+ const totalBalance = (productBalance || 0) - removeToBalance
128
+
129
+ /**
130
+ * Config context manager
131
+ */
132
+ const [stateConfig] = useConfig()
133
+
134
+ /**
135
+ * Max total product in cart by config
136
+ */
137
+ const maxCartProductConfig = (stateConfig.configs.max_product_amount ? parseInt(stateConfig.configs.max_product_amount) : 100) - totalBalance
138
+
139
+ /**
140
+ * Max total product in cart by config
141
+ */
142
+ let maxCartProductInventory = (product.product?.inventoried ? product.product?.quantity : undefined) - totalBalance
143
+
144
+ /**
145
+ * True if product is sold out
146
+ */
147
+ const isSoldOut = product.product?.inventoried && product.product?.quantity === 0
148
+
149
+ /**
150
+ * Fix if maxCartProductInventory is not valid
151
+ */
152
+ maxCartProductInventory = !isNaN(maxCartProductInventory) ? maxCartProductInventory : maxCartProductConfig
153
+
154
+ /**
155
+ * Max product quantity
156
+ */
157
+ const maxProductQuantity = Math.min(maxCartProductConfig, maxCartProductInventory)
158
+
159
+ /**
160
+ * alsea validation
161
+ */
162
+ const isAlsea = ['alsea', 'alsea-staging'].includes(ordering.project)
163
+
164
+ /**
165
+ * alsea custom options
166
+ */
167
+ const quesoYSalsaOptions = ['queso y salsa', 'queso mozzarella y salsa']
168
+
169
+ /**
170
+ * Init product cart status
171
+ * @param {object} product Product to init product cart status
172
+ */
173
+ const initProductCart = (product) => {
174
+ const ingredients = {}
175
+ for (const key in product.ingredients) {
176
+ const ingredient = product.ingredients[key]
177
+ ingredients[`id:${ingredient.id}`] = {
178
+ selected: true
179
+ }
180
+ }
181
+
182
+ const isEdit = props.productCart?.code
183
+ const maximumPerOrder = product?.maximum_per_order || 0
184
+ const minimumPerOrder = product?.minimum_per_order || 0
185
+ const productAddedToCartLengthUpdated = productAddedToCartLength || 0
186
+
187
+ const calculateStock = () => {
188
+ if (isEdit) {
189
+ return maximumPerOrder
190
+ }
191
+ return maximumPerOrder - productAddedToCartLengthUpdated
192
+ }
193
+
194
+ const stock = calculateStock()
195
+ const initialStock = Math.max(stock, 1)
196
+
197
+ const calculateInitialQuantity = () => {
198
+ if (isEdit) {
199
+ return props.productCart?.quantity
200
+ }
201
+ const isOverMaximum = (productAddedToCartLengthUpdated + minimumPerOrder) > maximumPerOrder
202
+ const hasOrderLimits = minimumPerOrder > 0 && maximumPerOrder > 0
203
+
204
+ if (isOverMaximum && hasOrderLimits) {
205
+ return maximumPerOrder - productAddedToCartLengthUpdated
206
+ }
207
+ return minimumPerOrder || initialStock
208
+ }
209
+
210
+ const initialQuantity = calculateInitialQuantity()
211
+
212
+ const newProductCart = {
213
+ ...props.productCart,
214
+ id: product.id,
215
+ price: product.price,
216
+ name: product.name,
217
+ businessId: props.businessId,
218
+ categoryId: product.category_id,
219
+ inventoried: product.inventoried,
220
+ stock: initialStock,
221
+ ingredients: props.productCart?.ingredients || ingredients,
222
+ options: props.productCart?.options || {},
223
+ comment: props.productCart?.comment || null,
224
+ quantity: initialQuantity,
225
+ favorite: product?.favorite
226
+ }
227
+ newProductCart.unitTotal = getUnitTotal(newProductCart)
228
+ newProductCart.total = newProductCart.unitTotal * newProductCart.quantity
229
+ setProductCart(newProductCart)
230
+ }
231
+
232
+ /**
233
+ * Get unit total for product cart
234
+ * @param {object} productCart Current product status
235
+ */
236
+ const getUnitTotal = (productCart) => {
237
+ let subtotal = 0
238
+ for (let i = 0; i < product.product?.extras?.length; i++) {
239
+ const extra = product.product?.extras[i]
240
+ for (let j = 0; j < extra.options?.length; j++) {
241
+ const option = extra.options[j]
242
+ for (let k = 0; k < option.suboptions?.length; k++) {
243
+ const suboption = option.suboptions[k]
244
+ if (productCart.options[`id:${option.id}`]?.suboptions[`id:${suboption.id}`]?.selected) {
245
+ const suboptionState = productCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`]
246
+ const quantity = option.allow_suboption_quantity ? suboptionState.quantity : 1
247
+ const price = option.with_half_option && suboption.half_price && suboptionState.position !== 'whole' ? suboption.half_price : suboption.price
248
+ subtotal += price * quantity
249
+ }
250
+ }
251
+ }
252
+ }
253
+ return product.product?.price + subtotal
254
+ }
255
+ /**
256
+ * Method to add, remove favorite info for user from API
257
+ */
258
+ const handleFavoriteProduct = async (productFav, isAdd = false) => {
259
+ if (!product || !user) return
260
+ showToast(ToastType.Info, t('LOADING', 'loading'))
261
+ try {
262
+ setProduct({ ...product, loading: true, error: null })
263
+ const productId = productFav?.id
264
+ const changes = { object_id: productId }
265
+ const requestOptions = {
266
+ method: isAdd ? 'POST' : 'DELETE',
267
+ headers: {
268
+ 'Content-Type': 'application/json',
269
+ Authorization: `Bearer ${token}`,
270
+ 'X-App-X': ordering.appId,
271
+ 'X-Socket-Id-X': socket?.getId()
272
+ },
273
+ ...(isAdd && { body: JSON.stringify(changes) })
274
+ }
275
+ const fetchEndpoint = isAdd
276
+ ? `${ordering.root}/users/${user?.id}/favorite_products`
277
+ : `${ordering.root}/users/${user.id}/favorite_products/${productId}`
278
+ const response = await fetch(fetchEndpoint, requestOptions)
279
+ const content = await response.json()
280
+ if (!content.error) {
281
+ loadProductWithOptions()
282
+ handleUpdateProducts && handleUpdateProducts(productId, { favorite: isAdd })
283
+ showToast(ToastType.Success, isAdd ? t('FAVORITE_ADDED', 'Favorite added') : t('FAVORITE_REMOVED', 'Favorite removed'))
284
+ } else {
285
+ setProduct({
286
+ ...product,
287
+ loading: false,
288
+ error: content.result
289
+ })
290
+ showToast(ToastType.Error, content.result)
291
+ }
292
+ } catch (error) {
293
+ setProduct({
294
+ ...product,
295
+ loading: false,
296
+ error: [error.message]
297
+ })
298
+ showToast(ToastType.Error, [error.message])
299
+ }
300
+ }
301
+
302
+ const isValidMoment = (date, format) => dayjs.utc(date, format).format(format) === date
303
+ /**
304
+ * Load product from API
305
+ */
306
+ const loadProductWithOptions = async () => {
307
+ try {
308
+ setProduct({ ...product, loading: true })
309
+ const source = {}
310
+ requestsState.product = source
311
+ const parameters = {
312
+ version: 'v2',
313
+ type: orderState.options?.type || 1
314
+ }
315
+ if (orderState.options?.moment && isValidMoment(orderState.options?.moment, 'YYYY-MM-DD HH:mm:ss')) {
316
+ const moment = dayjs.utc(orderState.options?.moment, 'YYYY-MM-DD HH:mm:ss').local().unix()
317
+ parameters.timestamp = moment
318
+ }
319
+ const { content: { result, error } } = await ordering
320
+ .businesses(props.businessId)
321
+ .categories(props.categoryId)
322
+ .products(props.productId)
323
+ .parameters(parameters)
324
+ .get({ cancelToken: source })
325
+
326
+ if (!error) {
327
+ setProduct({
328
+ ...product,
329
+ loading: false,
330
+ product: result
331
+ })
332
+ return
333
+ }
334
+ setProduct({
335
+ ...product,
336
+ loading: false,
337
+ error: [result]
338
+ })
339
+ } catch (err) {
340
+ setProduct({
341
+ ...product,
342
+ loading: false,
343
+ error: [err.message]
344
+ })
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Remove related option by respect_to
350
+ * @param {object} cart Current cart
351
+ * @param {number} suboptionId Suboption id
352
+ */
353
+ const removeRelatedOptions = (productCart, suboptionId) => {
354
+ product.product.extras.forEach(_extra => {
355
+ _extra.options.forEach(_option => {
356
+ if (_option.respect_to === suboptionId) {
357
+ const suboptions = productCart.options[`id:${_option.id}`]?.suboptions
358
+ if (suboptions) {
359
+ Object.keys(suboptions).map(suboptionKey => removeRelatedOptions(productCart, parseInt(suboptionKey.split(':')[1])))
360
+ }
361
+ if (productCart.options[`id:${_option.id}`]) {
362
+ productCart.options[`id:${_option.id}`].suboptions = {}
363
+ pizzaState[`option:${_option.id}`] = {}
364
+ }
365
+ }
366
+ })
367
+ })
368
+ }
369
+
370
+ /**
371
+ * Get changes for ingredients state
372
+ * @param {object} state Current ingrediente state
373
+ * @param {object} ingredient Current ingredient
374
+ */
375
+ const handleChangeIngredientState = (state, ingredient) => {
376
+ productCart.ingredients[`id:${ingredient.id}`] = state
377
+ setProductCart({
378
+ ...productCart,
379
+ ingredients: productCart.ingredients
380
+ })
381
+ }
382
+
383
+ /**
384
+ * Change product state with new suboption state
385
+ * @param {object} state New state with changes
386
+ * @param {object} suboption Suboption object
387
+ * @param {objecrt} option Option object
388
+ * @param {object} product Product object
389
+ */
390
+ const handleChangeSuboptionState = (state, suboption, option) => {
391
+ const newProductCart = JSON.parse(JSON.stringify(productCart))
392
+ if (!newProductCart.options) {
393
+ newProductCart.options = {}
394
+ }
395
+ if (!newProductCart.options[`id:${option.id}`]) {
396
+ newProductCart.options[`id:${option.id}`] = {
397
+ id: option.id,
398
+ name: option.name,
399
+ suboptions: {}
400
+ }
401
+ }
402
+ let newPizzaState = {}
403
+
404
+ if (!state.selected) {
405
+ delete newProductCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`]
406
+ removeRelatedOptions(newProductCart, suboption.id)
407
+ newPizzaState = handleVerifyPizzaState(state, suboption, option)
408
+ } else {
409
+ if (option.min === option.max && option.min === 1) {
410
+ const suboptions = newProductCart.options[`id:${option.id}`].suboptions
411
+ if (suboptions) {
412
+ Object.keys(suboptions).map(suboptionKey => removeRelatedOptions(newProductCart, parseInt(suboptionKey.split(':')[1])))
413
+ }
414
+ if (newProductCart.options[`id:${option.id}`]) {
415
+ newProductCart.options[`id:${option.id}`].suboptions = {}
416
+ }
417
+ }
418
+ newProductCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`] = state
419
+ }
420
+ let suboptionsArray = []
421
+ const _selectedSuboptions = selectedSuboptions
422
+ if (state.selected) {
423
+ for (const extra of product.product.extras) {
424
+ for (const option of extra.options) {
425
+ if (Object.keys(newProductCart?.options[`id:${option?.id}`]?.suboptions || {})?.length === 0) {
426
+ delete newProductCart?.options[`id:${option?.id}`]
427
+ }
428
+ }
429
+ }
430
+ if (newProductCart?.options) {
431
+ for (const extra of product.product.extras) {
432
+ for (const option of extra.options) {
433
+ for (const suboption of option.suboptions) {
434
+ if (newProductCart?.options[`id:${option?.id}`]) {
435
+ if (newProductCart?.options[`id:${option?.id}`]?.suboptions[`id:${suboption?.id}`]) {
436
+ _selectedSuboptions[`suboption:${suboption.id}`] = true
437
+ } else {
438
+ _selectedSuboptions[`suboption:${suboption.id}`] = false
439
+ }
440
+ } else {
441
+ _selectedSuboptions[`suboption:${suboption.id}`] = suboption?.preselected || (option?.max === 1 && option?.min === 1 && option?.suboptions?.length === 1)
442
+ }
443
+ }
444
+ }
445
+ }
446
+ }
447
+ const preselectedOptions = []
448
+ const preselectedSuboptions = []
449
+ for (const extra of product.product.extras) {
450
+ for (const option of extra.options) {
451
+ for (const suboption of option.suboptions) {
452
+ if (checkSuboptionsSelected(suboption?.id, _selectedSuboptions, dependsSuboptions)) {
453
+ preselectedOptions.push(option)
454
+ preselectedSuboptions.push(suboption)
455
+ }
456
+ }
457
+ }
458
+ }
459
+
460
+ const states = preselectedSuboptions.map((suboption, i) => {
461
+ const cartSuboption = newProductCart?.options[`id:${preselectedOptions[i]?.id}`]?.suboptions[`id:${suboption?.id}`] || suboption
462
+ const price = preselectedOptions[i]?.with_half_option && cartSuboption?.half_price && cartSuboption?.position !== 'whole'
463
+ ? cartSuboption.half_price
464
+ : cartSuboption.price
465
+
466
+ return {
467
+ id: cartSuboption.id,
468
+ name: cartSuboption.name,
469
+ position: state?.id === cartSuboption?.id ? state?.position : cartSuboption.position || 'whole',
470
+ price: state?.id === cartSuboption?.id ? state.price : price,
471
+ quantity: state?.id === cartSuboption?.id
472
+ ? state.quantity
473
+ : quesoYSalsaOptions.includes(preselectedOptions[i]?.name?.toLowerCase()) && isAlsea
474
+ ? cartSuboption?.quantity ?? 1
475
+ : cartSuboption?.quantity || 1,
476
+ selected: true,
477
+ total: state?.id === cartSuboption?.id ? state.total : price
478
+ }
479
+ })
480
+ preselectedOptions.map((option, i) => {
481
+ const defaultSuboption = {
482
+ option: option,
483
+ suboption: preselectedSuboptions[i],
484
+ state: states[i]
485
+ }
486
+ suboptionsArray = [...suboptionsArray, defaultSuboption]
487
+ })
488
+ newPizzaState = handleVerifyPizzaState(state, suboption, option, preselectedOptions, preselectedSuboptions, states)
489
+ }
490
+
491
+ let newBalance = Object.keys(newProductCart.options[`id:${option.id}`].suboptions).length
492
+ if (option.limit_suboptions_by_max) {
493
+ newBalance = Object.values(newProductCart.options[`id:${option.id}`].suboptions).reduce((count, suboption) => {
494
+ return count + suboption.quantity
495
+ }, 0)
496
+ }
497
+ const hasPreselectedFlow = suboptionsArray.filter(state => state?.suboption?.preselected)
498
+ if (newBalance <= option.max || (newPizzaState?.[`option:${option?.id}`]?.value <= option.max && option?.with_half_option)) {
499
+ newProductCart.options[`id:${option.id}`].balance = newBalance
500
+ newProductCart.unitTotal = getUnitTotal(newProductCart)
501
+ newProductCart.total = newProductCart.unitTotal * newProductCart.quantity
502
+ if (state.selected && hasPreselectedFlow?.length > 0) {
503
+ handleChangeSuboptionDefault(suboptionsArray, newPizzaState)
504
+ setSelectedSuboptions(_selectedSuboptions)
505
+ } else {
506
+ setProductCart(newProductCart)
507
+ }
508
+ }
509
+ }
510
+
511
+ const handleChangeSuboptionDefault = (defaultOptions, newPizzaState) => {
512
+ const newProductCart = JSON.parse(JSON.stringify(productCart))
513
+ if (!newProductCart.options) {
514
+ newProductCart.options = {}
515
+ }
516
+ defaultOptions.map(({ option, state, suboption }) => {
517
+ if (!newProductCart.options[`id:${option.id}`]) {
518
+ newProductCart.options[`id:${option.id}`] = {
519
+ id: option.id,
520
+ name: option.name,
521
+ suboptions: {}
522
+ }
523
+ }
524
+ if (!state?.selected) {
525
+ delete newProductCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`]
526
+ removeRelatedOptions(newProductCart, suboption.id)
527
+ } else {
528
+ if ((option.min === option.max) && option.min === 1) {
529
+ const suboptions = newProductCart.options[`id:${option.id}`].suboptions
530
+ if (suboptions) {
531
+ Object.keys(suboptions).map(suboptionKey => removeRelatedOptions(newProductCart, parseInt(suboptionKey.split(':')[1])))
532
+ }
533
+ if (newProductCart.options[`id:${option.id}`]) {
534
+ newProductCart.options[`id:${option.id}`].suboptions = {}
535
+ }
536
+ }
537
+ newProductCart.options[`id:${option.id}`].suboptions[`id:${suboption.id}`] = state
538
+ }
539
+ let newBalance = Object.keys(newProductCart.options[`id:${option.id}`].suboptions).length
540
+ if (option.limit_suboptions_by_max) {
541
+ newBalance = Object.values(newProductCart.options[`id:${option.id}`].suboptions).reduce((count, suboption) => {
542
+ return count + suboption.quantity
543
+ }, 0)
544
+ }
545
+
546
+ if (newBalance <= option.max || (newPizzaState?.[`option:${option.id}`]?.value <= option.max && option?.with_half_option)) {
547
+ newProductCart.options[`id:${option.id}`].balance = newBalance
548
+ newProductCart.unitTotal = getUnitTotal(newProductCart)
549
+ newProductCart.total = newProductCart.unitTotal * newProductCart.quantity
550
+ }
551
+ })
552
+ setProductCart(newProductCart)
553
+ }
554
+
555
+ /**
556
+ * Change product state with new comment state
557
+ * @param {object} e Product comment
558
+ */
559
+ const handleChangeCommentState = (e) => {
560
+ const comment = e.target.value ?? ''
561
+ productCart.comment = comment.trim()
562
+ setProductCart({
563
+ ...productCart,
564
+ comment: comment.trim()
565
+ })
566
+ }
567
+
568
+ /**
569
+ * Check options to get errors
570
+ */
571
+ const checkErrors = () => {
572
+ const errors = {}
573
+ if (!product?.product) {
574
+ return errors
575
+ }
576
+ product?.product?.extras?.forEach(extra => {
577
+ extra?.options?.map(option => {
578
+ const suboptions = productCart.options[`id:${option.id}`]?.suboptions
579
+ const quantity = suboptions
580
+ ? option?.with_half_option
581
+ ? pizzaState?.[`option:${option?.id}`]?.value
582
+ : (option.limit_suboptions_by_max
583
+ ? Object.values(suboptions).reduce((count, suboption) => {
584
+ return count + suboption.quantity
585
+ }, 0)
586
+ : Object.keys(suboptions)?.length)
587
+ : 0
588
+ let evaluateRespectTo = false
589
+ if (option.respect_to && productCart.options) {
590
+ const options = productCart?.options
591
+ for (const key in options) {
592
+ const _option = options[key]
593
+ if (_option.suboptions[`id:${option.respect_to}`]?.selected) {
594
+ evaluateRespectTo = true
595
+ break
596
+ }
597
+ }
598
+ }
599
+ const evaluate = option.respect_to ? evaluateRespectTo : true
600
+ if (option?.suboptions?.length > 0 && evaluate) {
601
+ if (option.min > quantity) {
602
+ errors[`id:${option.id}`] = true
603
+ } else if (option.max < quantity && (option?.with_half_option && isAlsea && (option.max + 0.5 < quantity))) {
604
+ errors[`id:${option.id}`] = true
605
+ }
606
+ }
607
+ })
608
+ })
609
+ setErrors(errors)
610
+ return errors
611
+ }
612
+
613
+ /**
614
+ * Handle when click on save product
615
+ */
616
+ const handleSave = async (values) => {
617
+ try {
618
+ setProductLoading && setProductLoading(true)
619
+ if (handleCustomSave) {
620
+ handleCustomSave && handleCustomSave()
621
+ }
622
+ const errors = checkErrors()
623
+ const isMultiProduct = JSON.parse(product?.product?.meta || '{}')?.external_type === 'coupon'
624
+ const hasAlreadyCoupon = cart?.metafields?.find?.(meta => meta?.key === 'pulse_coupons')?.value && isMultiProduct
625
+
626
+ if ((Object.keys(errors).length === 0 || isService) && !hasAlreadyCoupon) {
627
+ let successful = true
628
+ if (useOrderContext) {
629
+ successful = false
630
+ const changes = cart || { business_id: props.businessId }
631
+ const currentProduct = !isService
632
+ ? { ...productCart }
633
+ : {
634
+ ...productCart,
635
+ professional_id: values?.professional?.id,
636
+ service_start: values?.serviceTime ?? orderState.options?.moment
637
+ }
638
+ onSave(productCart, !props.productCart?.code)
639
+ if (!props.productCart?.code) {
640
+ successful =
641
+ isMultiProduct
642
+ ? await addMultiProduct(currentProduct, changes, false)
643
+ : await addProduct(currentProduct, changes, false)
644
+ } else {
645
+ successful = await updateProduct(currentProduct, changes, false)
646
+ if (successful) {
647
+ events.emit('product_edited', currentProduct)
648
+ }
649
+ }
650
+ }
651
+ if (successful) {
652
+ if (isService) {
653
+ const updatedProfessional = JSON.parse(JSON.stringify(values?.professional))
654
+ const duration = product?.product?.duration
655
+ updatedProfessional.busy_times.push({
656
+ start: values?.serviceTime,
657
+ end: moment(values?.serviceTime).add(duration, 'minutes').format('YYYY-MM-DD HH:mm:ss'),
658
+ duration
659
+ })
660
+ handleUpdateProfessionals && handleUpdateProfessionals(updatedProfessional)
661
+ handleChangeProfessional && handleChangeProfessional(updatedProfessional)
662
+ }
663
+ } else {
664
+ showToast(
665
+ ToastType.Error,
666
+ !props.productCart?.code ? t('FAILED_TO_ADD_PRODUCT', 'Failed to add product') : t('FAILED_TO_UPDATE_PRODUCT', 'Failed to update product'),
667
+ 5000
668
+ )
669
+ }
670
+ }
671
+ if (hasAlreadyCoupon) {
672
+ showToast(
673
+ ToastType.Error,
674
+ t('COUPON_ALREADY_ADDED', 'You have a coupon already added')
675
+ )
676
+ }
677
+ setProductLoading && setProductLoading(false)
678
+ } catch (err) {
679
+ showToast(
680
+ ToastType.Error,
681
+ !props.productCart?.code ? t('FAILED_TO_ADD_PRODUCT', 'Failed to add product') : t('FAILED_TO_UPDATE_PRODUCT', 'Failed to update product')
682
+ )
683
+ setProductLoading && setProductLoading(false)
684
+ }
685
+ }
686
+
687
+ const handleCreateGuestUser = async (values) => {
688
+ try {
689
+ setActionStatus({ ...actionStatus, loading: true })
690
+ const { content: { error, result } } = await ordering.users().save(values)
691
+ if (!error) {
692
+ setActionStatus({ error: null, loading: false })
693
+ login({
694
+ user: result,
695
+ token: result.session?.access_token
696
+ })
697
+ } else {
698
+ setActionStatus({ error: result, loading: false })
699
+ }
700
+ } catch (err) {
701
+ setActionStatus({ error: err.message, loading: false })
702
+ }
703
+ }
704
+
705
+ const increment = () => {
706
+ if (maxProductQuantity <= 0 || productCart.quantity >= maxProductQuantity) {
707
+ return
708
+ }
709
+ productCart.quantity++
710
+ productCart.unitTotal = getUnitTotal(productCart)
711
+ productCart.total = productCart.unitTotal * productCart.quantity
712
+ setProductCart({
713
+ ...productCart
714
+ })
715
+ }
716
+
717
+ const decrement = () => {
718
+ if (productCart.quantity === 0) {
719
+ return
720
+ }
721
+ productCart.quantity--
722
+ productCart.unitTotal = getUnitTotal(productCart)
723
+ productCart.total = productCart.unitTotal * productCart.quantity
724
+ setProductCart({
725
+ ...productCart
726
+ })
727
+ }
728
+
729
+ const handleChangeProductCartQuantity = (quantity) => {
730
+ if (maxProductQuantity <= 0 || quantity > maxProductQuantity) {
731
+ return
732
+ }
733
+ productCart.quantity = quantity || 0
734
+ productCart.total = productCart.unitTotal * productCart.quantity
735
+ setProductCart({
736
+ ...productCart
737
+ })
738
+ }
739
+
740
+ /**
741
+ * Check if option must show
742
+ * @param {object} option Option to check
743
+ */
744
+ const showOption = (option) => {
745
+ let showOption = true
746
+ if (option.respect_to) {
747
+ showOption = false
748
+ if (productCart.options) {
749
+ const options = productCart.options
750
+ for (const key in options) {
751
+ const _option = options[key]
752
+ if (_option.suboptions[`id:${option.respect_to}`]?.selected) {
753
+ showOption = true
754
+ break
755
+ }
756
+ }
757
+ }
758
+ }
759
+
760
+ if (option?.suboptions?.length === 0) showOption = false
761
+
762
+ return showOption
763
+ }
764
+
765
+ /**
766
+ * Load professionals from API
767
+ */
768
+ const getProfessionalList = async () => {
769
+ try {
770
+ setProfessionalListState({ ...professionalListState, loading: true })
771
+ const { content: { result, error } } = await ordering
772
+ .businesses(props.businessId)
773
+ .select(['id', 'professionals'])
774
+ .get()
775
+
776
+ if (!error) {
777
+ setProfessionalListState({
778
+ ...professionalListState,
779
+ loading: false,
780
+ professionals: result?.professionals ?? []
781
+ })
782
+ return
783
+ }
784
+ setProfessionalListState({
785
+ ...professionalListState,
786
+ loading: false,
787
+ error: [result]
788
+ })
789
+ } catch (err) {
790
+ setProfessionalListState({
791
+ ...professionalListState,
792
+ loading: false,
793
+ error: [err.message]
794
+ })
795
+ }
796
+ }
797
+ /**
798
+ * function to verify position of pizza ingredients
799
+ * @param {object} newProductCart cart updated with suboptions
800
+ */
801
+ const handleVerifyPizzaState = (state, suboption, option, preselectedOptions, preselectedSuboptions, states) => {
802
+ let newPizzaState = {}
803
+ if (state?.selected) {
804
+ preselectedOptions.map((option, i) => {
805
+ if (option?.with_half_option) {
806
+ newPizzaState = {
807
+ ...newPizzaState,
808
+ [`option:${option?.id}`]: {
809
+ ...newPizzaState?.[`option:${option?.id}`],
810
+ [`suboption:${preselectedSuboptions[i]?.id}`]:
811
+ isAlsea
812
+ ? (states[i]?.position === 'whole' ? 1 : 0.5) + (states[i].quantity >= 2 ? 0.5 : 0)
813
+ : (states[i]?.position === 'whole' ? 1 : 0.5) * states[i].quantity
814
+ }
815
+ }
816
+ const suboptionValue = isAlsea
817
+ ? ((states[i]?.position === 'whole' || (option?.max === 1 && option?.min === 1) ? 1 : 0.5) + (states[i].quantity >= 2 ? 0.5 : 0))
818
+ : ((states[i]?.position === 'whole' || (option?.max === 1 && option?.min === 1) ? 1 : 0.5) * states[i].quantity)
819
+
820
+ const value = suboptionValue + (newPizzaState[`option:${option?.id}`].value || 0)
821
+ newPizzaState[`option:${option?.id}`].value = value
822
+ }
823
+ })
824
+ } else {
825
+ newPizzaState = {
826
+ ...pizzaState,
827
+ [`option:${option?.id}`]: {
828
+ ...pizzaState[`option:${option?.id}`],
829
+ value: 0
830
+ }
831
+ }
832
+ delete newPizzaState?.[`option:${option?.id}`]?.[`suboption:${suboption?.id}`]
833
+ const value = Object?.values(newPizzaState?.[`option:${option?.id}`] || {})?.reduce((acc, value) => acc + value, 0)
834
+ newPizzaState[`option:${option?.id}`].value = value
835
+ }
836
+ setPizzaState(newPizzaState)
837
+ return newPizzaState
838
+ }
839
+ /**
840
+ * Init product cart when product changed
841
+ */
842
+ useEffect(() => {
843
+ if (product.product) {
844
+ initProductCart(product.product)
845
+ }
846
+ }, [product.product])
847
+
848
+ /**
849
+ * Check error when product state changed
850
+ */
851
+ useEffect(() => {
852
+ checkErrors()
853
+ }, [productCart])
854
+
855
+ /**
856
+ * Listening product changes
857
+ */
858
+ useEffect(() => {
859
+ if (props?.product?.load_type === 'lazy') return
860
+ setProduct({ ...product, product: props.product })
861
+ }, [props.product])
862
+
863
+ /**
864
+ * Check if there is an option required with one suboption
865
+ */
866
+
867
+ const checkSuboptionsSelected = (suboptionId, _selectedSuboptions, _dependsSuboptions, count = 0) => {
868
+ if (count > 100) {
869
+ return false
870
+ }
871
+ if (!_selectedSuboptions[`suboption:${suboptionId}`]) {
872
+ return false
873
+ }
874
+ const respectTo = _dependsSuboptions[`suboption:${suboptionId}`] ?? null
875
+ if (respectTo === null) {
876
+ return _selectedSuboptions[`suboption:${suboptionId}`]
877
+ }
878
+ return checkSuboptionsSelected(respectTo, _selectedSuboptions, _dependsSuboptions, count++)
879
+ }
880
+
881
+ useEffect(() => {
882
+ if (!product?.loading && product?.product && product.product?.extras?.length > 0) {
883
+ const _selectedSuboptions = {}
884
+ const _dependsSuboptions = {}
885
+ const preselectedOptions = []
886
+ const preselectedSuboptions = []
887
+ for (const extra of product?.product?.extras) {
888
+ if (extra?.options) {
889
+ for (const option of extra?.options) {
890
+ for (const suboption of option?.suboptions) {
891
+ _selectedSuboptions[`suboption:${suboption.id}`] =
892
+ (suboption.preselected ||
893
+ (option?.max === 1 && option?.min === 1 && option?.suboptions?.length === 1)) &&
894
+ (!editMode || !!props.productCart?.options[`id:${option?.id}`]?.suboptions[`id:${suboption?.id}`])
895
+ _dependsSuboptions[`suboption:${suboption.id}`] = option?.conditioned && option?.respect_to !== null ? option?.respect_to : null
896
+ }
897
+ }
898
+ }
899
+ }
900
+
901
+ if (editMode && props?.productCart) {
902
+ Object.values(props?.productCart?.options)?.map(option => Object.values(option?.suboptions)?.map(suboption => {
903
+ _selectedSuboptions[`suboption:${suboption.id}`] = true
904
+ }))
905
+ }
906
+
907
+ for (const extra of product?.product?.extras) {
908
+ if (extra?.options) {
909
+ for (const option of extra?.options) {
910
+ for (const suboption of option?.suboptions) {
911
+ if (checkSuboptionsSelected(suboption?.id, _selectedSuboptions, _dependsSuboptions)) {
912
+ preselectedOptions.push(option)
913
+ preselectedSuboptions.push(suboption)
914
+ }
915
+ }
916
+ }
917
+ }
918
+ }
919
+ setSelectedSuboptions(_selectedSuboptions)
920
+ setDependsSuboptions(_dependsSuboptions)
921
+ if (!preselectedOptions?.length) {
922
+ return
923
+ }
924
+ let states = {}
925
+ if (editMode && props?.productCart) {
926
+ const cartSuboptions = Object.values(props?.productCart?.options)?.map(option => Object.values(option?.suboptions))?.flat()
927
+ states = cartSuboptions.map((suboption, i) => {
928
+ const price = preselectedOptions[i]?.with_half_option && suboption?.half_price && suboption?.position !== 'whole'
929
+ ? suboption.half_price
930
+ : suboption.price
931
+ return {
932
+ id: suboption.id,
933
+ name: suboption.name,
934
+ position: suboption.position || 'whole',
935
+ price,
936
+ quantity: suboption.quantity,
937
+ selected: true,
938
+ total: price
939
+ }
940
+ })
941
+ } else {
942
+ states = preselectedSuboptions.map((suboption, i) => {
943
+ const price = preselectedOptions[i]?.with_half_option && suboption?.half_price && suboption?.position !== 'whole'
944
+ ? suboption.half_price
945
+ : suboption.price
946
+
947
+ return {
948
+ id: suboption.id,
949
+ name: suboption.name,
950
+ position: suboption.position || 'whole',
951
+ price,
952
+ quantity: 1,
953
+ selected: true,
954
+ total: price
955
+ }
956
+ })
957
+ }
958
+
959
+ let suboptionsArray = []
960
+ let newPizzaState = {}
961
+ preselectedOptions.map((option, i) => {
962
+ const defaultSuboption = {
963
+ option: option,
964
+ suboption: preselectedSuboptions[i],
965
+ state: states?.find((state) => state?.id === preselectedSuboptions[i]?.id)
966
+ }
967
+ suboptionsArray = [...suboptionsArray, defaultSuboption]
968
+ if (option?.with_half_option) {
969
+ newPizzaState = {
970
+ ...newPizzaState,
971
+ [`option:${option?.id}`]: {
972
+ ...newPizzaState?.[`option:${option?.id}`],
973
+ [`suboption:${preselectedSuboptions[i]?.id}`]: isAlsea
974
+ ? (states[i]?.position === 'whole' ? 1 : 0.5) + (states[i].quantity >= 2 ? 0.5 : 0)
975
+ : (states[i]?.position === 'whole' ? 1 : 0.5) * states[i].quantity
976
+ }
977
+ }
978
+ const suboptionValue = isAlsea
979
+ ? ((states[i]?.position === 'whole' || (option?.max === 1 && option?.min === 1) ? 1 : 0.5) + (states[i].quantity >= 2 ? 0.5 : 0))
980
+ : ((states[i]?.position === 'whole' || (option?.max === 1 && option?.min === 1) ? 1 : 0.5) * states[i].quantity)
981
+
982
+ const value = suboptionValue + (newPizzaState[`option:${option?.id}`].value || 0)
983
+ newPizzaState[`option:${option?.id}`].value = value
984
+ }
985
+ })
986
+ setPizzaState(newPizzaState)
987
+ setDefaultSubOptions(suboptionsArray)
988
+ setCustomDefaultSubOptions(suboptionsArray)
989
+ }
990
+ }, [JSON.stringify(product.product), product?.loading])
991
+
992
+ if (isStarbucks) {
993
+ useEffect(() => {
994
+ if (product?.product && Object.keys(product?.product).length) {
995
+ const options = [].concat(...product.product?.extras?.map(extra => extra?.options?.filter(
996
+ option => (
997
+ option.name === 'Tamaño' &&
998
+ option.suboptions.filter(suboption => suboption.name === 'Grande (16oz - 437ml)').length === 1
999
+ )
1000
+ )))
1001
+ if (!options?.length) {
1002
+ return
1003
+ }
1004
+ const suboptions = []
1005
+ .concat(...options.map(option => option.suboptions))
1006
+ .filter(suboption => suboption.name === 'Grande (16oz - 437ml)')
1007
+ const states = suboptions.map((suboption, i) => {
1008
+ const price = options[i].with_half_option && suboption.half_price && suboption?.position !== 'whole'
1009
+ ? suboption.half_price
1010
+ : suboption.price
1011
+
1012
+ return {
1013
+ id: suboption.id,
1014
+ name: suboption.name,
1015
+ position: suboption.position || 'whole',
1016
+ price,
1017
+ quantity: 1,
1018
+ selected: true,
1019
+ total: price
1020
+ }
1021
+ })
1022
+ const defaultOptions = options.map((option, i) => {
1023
+ return {
1024
+ option: option,
1025
+ suboption: suboptions[i],
1026
+ state: states[i]
1027
+ }
1028
+ })
1029
+ setDefaultSubOptions([...customDefaultSubOptions, ...defaultOptions])
1030
+ }
1031
+ }, [customDefaultSubOptions])
1032
+ }
1033
+ /**
1034
+ * Check if defaultSubOption has content to set product Cart
1035
+ */
1036
+ useEffect(() => {
1037
+ if (defaultSubOptions?.length) {
1038
+ handleChangeSuboptionDefault(defaultSubOptions)
1039
+ }
1040
+ }, [JSON.stringify(defaultSubOptions)])
1041
+
1042
+ /**
1043
+ * Load product on component mounted
1044
+ */
1045
+ useEffect(() => {
1046
+ if (!props.product && (!props.businessId || !props.categoryId || !props.productId)) {
1047
+ throw new Error('`businessId` && `categoryId` && `productId` are required if `product` was not provided.')
1048
+ }
1049
+ if ((props.product && props.product?.load_type === 'lazy' && props.businessId && props.categoryId && props.productId) ||
1050
+ (!props.product && props.businessId && props.categoryId && props.productId)
1051
+ ) {
1052
+ loadProductWithOptions()
1053
+ }
1054
+ return () => {
1055
+ if (requestsState.product) {
1056
+ requestsState.product.cancel()
1057
+ }
1058
+ }
1059
+ }, [])
1060
+
1061
+ useEffect(() => {
1062
+ if (!isService) return
1063
+
1064
+ if (isCartProduct) {
1065
+ getProfessionalList()
1066
+ } else {
1067
+ setProfessionalListState({
1068
+ ...professionalListState,
1069
+ professionals: professionalList
1070
+ })
1071
+ }
1072
+ }, [isService, isCartProduct, professionalList])
1073
+
1074
+ return (
1075
+ <>
1076
+ {
1077
+ UIComponent && (
1078
+ <UIComponent
1079
+ {...props}
1080
+ productObject={product}
1081
+ productCart={productCart}
1082
+ errors={errors}
1083
+ editMode={editMode}
1084
+ isSoldOut={isSoldOut}
1085
+ actionStatus={actionStatus}
1086
+ maxProductQuantity={maxProductQuantity}
1087
+ pizzaState={pizzaState}
1088
+ setPizzaState={setPizzaState}
1089
+ increment={increment}
1090
+ decrement={decrement}
1091
+ handleChangeProductCartQuantity={handleChangeProductCartQuantity}
1092
+ handleSave={handleSave}
1093
+ showOption={showOption}
1094
+ handleCreateGuestUser={handleCreateGuestUser}
1095
+ handleFavoriteProduct={handleFavoriteProduct}
1096
+ handleChangeIngredientState={handleChangeIngredientState}
1097
+ handleChangeSuboptionState={handleChangeSuboptionState}
1098
+ handleChangeCommentState={handleChangeCommentState}
1099
+ professionalListState={professionalListState}
1100
+ cart2={props.productCart}
1101
+ isAlsea={isAlsea}
1102
+ quesoYSalsaOptions={quesoYSalsaOptions}
1103
+ />
1104
+ )
1105
+ }
1106
+ </>
1107
+ )
1108
+ }
1109
+
1110
+ ProductForm.propTypes = {
1111
+ /**
1112
+ * UI Component, this must be containt all graphic elements and use parent props
1113
+ */
1114
+ UIComponent: PropTypes.elementType,
1115
+ /**
1116
+ * `businessId`
1117
+ */
1118
+ businessId: PropTypes.number.isRequired,
1119
+ /**
1120
+ * `categoryId` is required if `product` prop is not present
1121
+ */
1122
+ categoryId: PropTypes.number,
1123
+ /**
1124
+ * `productId` is required if `product` prop is not present
1125
+ */
1126
+ productId: PropTypes.number,
1127
+ /**
1128
+ * `product` is required if `businessId`, `categoryId` or `productId` is not present
1129
+ */
1130
+ product: PropTypes.object,
1131
+ /**
1132
+ * Product from cart
1133
+ */
1134
+ productCart: PropTypes.object,
1135
+ /**
1136
+ * useOrderContext
1137
+ */
1138
+ useOrderContext: PropTypes.bool,
1139
+ /**
1140
+ * Function to save event
1141
+ */
1142
+ onSave: PropTypes.func
1143
+ }
1144
+
1145
+ ProductForm.defaultProps = {
1146
+ productCart: {},
1147
+ useOrderContext: true,
1148
+ balance: 0
1149
+ }