diff --git a/erpnext/e_commerce/doctype/wishlist/wishlist.py b/erpnext/e_commerce/doctype/wishlist/wishlist.py index 7527c6f415..83bdff6115 100644 --- a/erpnext/e_commerce/doctype/wishlist/wishlist.py +++ b/erpnext/e_commerce/doctype/wishlist/wishlist.py @@ -10,18 +10,22 @@ class Wishlist(Document): pass @frappe.whitelist() -def add_to_wishlist(item_code, price): +def add_to_wishlist(item_code, price, formatted_price=None): """Insert Item into wishlist.""" web_item_data = frappe.db.get_value("Website Item", {"item_code": item_code}, - ["image", "website_warehouse", "name", "item_name"], as_dict=1) + ["image", "website_warehouse", "name", "item_name", "item_group", "route"] + , as_dict=1) wished_item_dict = { "item_code": item_code, "item_name": web_item_data.get("item_name"), + "item_group": web_item_data.get("item_group"), "website_item": web_item_data.get("name"), "price": frappe.utils.flt(price), + "formatted_price": formatted_price, "image": web_item_data.get("image"), - "website_warehouse": web_item_data.get("website_warehouse") + "warehouse": web_item_data.get("website_warehouse"), + "route": web_item_data.get("route") } if not frappe.db.exists("Wishlist", frappe.session.user): diff --git a/erpnext/e_commerce/doctype/wishlist_items/wishlist_items.json b/erpnext/e_commerce/doctype/wishlist_items/wishlist_items.json index 18065a8861..0b132737b3 100644 --- a/erpnext/e_commerce/doctype/wishlist_items/wishlist_items.json +++ b/erpnext/e_commerce/doctype/wishlist_items/wishlist_items.json @@ -9,13 +9,16 @@ "website_item", "column_break_3", "item_name", + "item_group", "item_details_section", "description", "column_break_7", - "section_break_8", - "price", + "route", "image", "image_view", + "section_break_8", + "price", + "formatted_price", "warehouse_section", "warehouse" ], @@ -101,12 +104,28 @@ "fieldname": "price", "fieldtype": "Float", "label": "Price" + }, + { + "fieldname": "item_group", + "fieldtype": "Link", + "label": "Item Group", + "options": "Item Group" + }, + { + "fieldname": "route", + "fieldtype": "Small Text", + "label": "Route" + }, + { + "fieldname": "formatted_price", + "fieldtype": "Data", + "label": "Formatted Price" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-03-12 18:23:03.487891", + "modified": "2021-03-15 16:37:40.405333", "modified_by": "Administrator", "module": "E-commerce", "name": "Wishlist Items", diff --git a/erpnext/e_commerce/product_query.py b/erpnext/e_commerce/product_query.py index 28d33e6e81..c37f8fb6b2 100644 --- a/erpnext/e_commerce/product_query.py +++ b/erpnext/e_commerce/product_query.py @@ -81,7 +81,7 @@ class ProductQuery: item.in_stock = "green" if stock_qty else "red" item.wished = False - if frappe.db.exists("Wishlist Items", {"item_code": item.item_code}): + if frappe.db.exists("Wishlist Items", {"item_code": item.item_code, "parent": frappe.session.user}): item.wished = True return result diff --git a/erpnext/public/js/shopping_cart.js b/erpnext/public/js/shopping_cart.js index bcfa983e4a..b57862b93a 100644 --- a/erpnext/public/js/shopping_cart.js +++ b/erpnext/public/js/shopping_cart.js @@ -186,5 +186,40 @@ $.extend(shopping_cart, { $(".shopping-cart").toggleClass('hidden', r.message ? false : true); } }); + }, + + animate_add_to_cart(button) { + // Create 'added to cart' animation + let btn_id = "#" + button[0].id; + this.toggle_button_class(button, 'not-added', 'added-to-cart'); + $(btn_id).text('Added to Cart'); + + // undo + setTimeout(() => { + this.toggle_button_class(button, 'added-to-cart', 'not-added'); + $(btn_id).text('Add to Cart'); + }, 2000); + }, + + toggle_button_class(button, remove, add) { + button.removeClass(remove); + button.addClass(add); + }, + + bind_add_to_cart_action() { + $('.page_content').on('click', '.btn-add-to-cart-list', (e) => { + const $btn = $(e.currentTarget); + $btn.prop('disabled', true); + + this.animate_add_to_cart($btn); + + const item_code = $btn.data('item-code'); + erpnext.shopping_cart.update_cart({ + item_code, + qty: 1 + }); + + }); } + }); diff --git a/erpnext/public/js/wishlist.js b/erpnext/public/js/wishlist.js index 328bdb996d..6ab1906b60 100644 --- a/erpnext/public/js/wishlist.js +++ b/erpnext/public/js/wishlist.js @@ -1,13 +1,12 @@ -frappe.provide("erpnext.e_commerce"); -var wishlist = erpnext.e_commerce; +frappe.provide("erpnext.wishlist"); +var wishlist = erpnext.wishlist; -frappe.ready(function() { - $(".wishlist").toggleClass('hidden', true); - wishlist.set_wishlist_count(); -}); +frappe.provide("erpnext.shopping_cart"); +var shopping_cart = erpnext.shopping_cart; $.extend(wishlist, { set_wishlist_count: function() { + // set badge count for wishlist icon var wish_count = frappe.get_cookie("wish_count"); if(frappe.session.user==="Guest") { wish_count = 0; @@ -35,5 +34,127 @@ $.extend(wishlist, { } else { $badge.remove(); } + }, + + bind_move_to_cart_action: function() { + // move item to cart from wishlist + $('.page_content').on("click", ".btn-add-to-cart", (e) => { + const $move_to_cart_btn = $(e.currentTarget); + let item_code = $move_to_cart_btn.data("item-code"); + + shopping_cart.shopping_cart_update({ + item_code, + qty: 1, + cart_dropdown: true + }); + + let success_action = function() { + const $card_wrapper = $move_to_cart_btn.closest(".item-card"); + $card_wrapper.addClass("wish-removed"); + }; + let args = { item_code: item_code }; + this.add_remove_from_wishlist("remove", args, success_action, null, true); + }); + }, + + bind_remove_action: function() { + // remove item from wishlist + $('.page_content').on("click", ".remove-wish", (e) => { + const $remove_wish_btn = $(e.currentTarget); + let item_code = $remove_wish_btn.data("item-code"); + + let success_action = function() { + const $card_wrapper = $remove_wish_btn.closest(".item-card"); + $card_wrapper.addClass("wish-removed"); + }; + let args = { item_code: item_code }; + this.add_remove_from_wishlist("remove", args, success_action); + }); + }, + + bind_wishlist_action() { + // 'wish'('like') or 'unwish' item in product listing + $('.page_content').on('click', '.like-action', (e) => { + const $btn = $(e.currentTarget); + const $wish_icon = $btn.find('.wish-icon'); + let me = this; + + let success_action = function() { + erpnext.wishlist.set_wishlist_count(); + }; + + if ($wish_icon.hasClass('wished')) { + // un-wish item + $btn.removeClass("like-animate"); + this.toggle_button_class($wish_icon, 'wished', 'not-wished'); + + let args = { item_code: $btn.data('item-code') }; + let failure_action = function() { + me.toggle_button_class($wish_icon, 'not-wished', 'wished'); + }; + this.add_remove_from_wishlist("remove", args, success_action, failure_action); + } else { + // wish item + $btn.addClass("like-animate"); + this.toggle_button_class($wish_icon, 'not-wished', 'wished'); + + let args = { + item_code: $btn.data('item-code'), + price: $btn.data('price'), + formatted_price: $btn.data('formatted-price') + }; + let failure_action = function() { + me.toggle_button_class($wish_icon, 'wished', 'not-wished'); + }; + this.add_remove_from_wishlist("add", args, success_action, failure_action); + } + }); + }, + + toggle_button_class(button, remove, add) { + button.removeClass(remove); + button.addClass(add); + }, + + add_remove_from_wishlist(action, args, success_action, failure_action, async=false) { + /* AJAX call to add or remove Item from Wishlist + action: "add" or "remove" + args: args for method (item_code, price, formatted_price), + success_action: method to execute on successs, + failure_action: method to execute on failure, + async: make call asynchronously (true/false). */ + let method = "erpnext.e_commerce.doctype.wishlist.wishlist.add_to_wishlist"; + if (action === "remove") { + method = "erpnext.e_commerce.doctype.wishlist.wishlist.remove_from_wishlist"; + } + + frappe.call({ + type: "POST", + method: method, + args: args, + callback: function (r) { + if (r.exc) { + if (failure_action && (typeof failure_action === 'function')) {failure_action();} + frappe.msgprint({ + message: __("Sorry, something went wrong. Please refresh."), + indicator: "red", title: __("Note") + }); + } else { + if (success_action && (typeof success_action === 'function')) {success_action();} + } + } + }); } + +}); + +frappe.ready(function() { + if (window.location.pathname !== "/wishlist") { + $(".wishlist").toggleClass('hidden', true); + wishlist.set_wishlist_count(); + } else { + wishlist.bind_move_to_cart_action(); + wishlist.bind_remove_action(); + } + }); \ No newline at end of file diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss index 3d66f146c0..6a96e41256 100644 --- a/erpnext/public/scss/shopping_cart.scss +++ b/erpnext/public/scss/shopping_cart.scss @@ -648,3 +648,27 @@ body.product-page { color: white; } } + +.wishlist-cart-not-added { + color: var(--blue-500); + background-color: white; + border: 1px solid var(--blue-500); + --icon-stroke: var(--blue-500); + + &:hover { + background-color: var(--blue-500); + color: white; + --icon-stroke: white; + } +} + +.remove-wish { + &:hover { + background-color: var(--gray-100); + border: 1px solid var(--icon-stroke); + } +} + +.wish-removed { + display: none; +} diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html index 743daaf7e1..aec201e0d9 100644 --- a/erpnext/templates/includes/macros.html +++ b/erpnext/templates/includes/macros.html @@ -118,7 +118,6 @@ 'text-left': align == 'Left' or is_featured, }) -%}