[hub][vue] Saved Products Page, remote item card
- also undo unfavouriting items
This commit is contained in:
parent
fe41713974
commit
00175eab8e
@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<div class="col-md-3 col-sm-4 col-xs-6 hub-card-container">
|
||||
<div class="hub-card is_local"
|
||||
<div v-if="item.seen" class="col-md-3 col-sm-4 col-xs-6 hub-card-container">
|
||||
<div class="hub-card"
|
||||
@click="on_click(item_id)"
|
||||
>
|
||||
<div class="hub-card-header flex justify-between">
|
||||
<div>
|
||||
<div class="ellipsis" :style="{ width: '85%' }">
|
||||
<div class="hub-card-title ellipsis bold">{{ title }}</div>
|
||||
<div class="hub-card-subtitle ellipsis text-muted" v-html='subtitle'></div>
|
||||
</div>
|
||||
<i v-if="allow_clear"
|
||||
class="octicon octicon-x text-extra-muted"
|
||||
@click="$emit('remove-item', item_id)"
|
||||
@click.stop="$emit('remove-item', item_id)"
|
||||
>
|
||||
</i>
|
||||
</div>
|
||||
<div class="hub-card-body">
|
||||
<img class="hub-card-image" :src="item.image"/>
|
||||
<div class="hub-card-overlay">
|
||||
<div class="hub-card-overlay-body">
|
||||
<div class="hub-card-overlay-button" style="right: 15px; bottom: 15px;">
|
||||
<div v-if="is_local" class="hub-card-overlay-body">
|
||||
<div class="hub-card-overlay-button">
|
||||
<button class="btn btn-default zoom-view">
|
||||
<i class="octicon octicon-pencil text-muted"></i>
|
||||
</button>
|
||||
@ -34,13 +34,28 @@
|
||||
|
||||
export default {
|
||||
name: 'item-card',
|
||||
props: ['item', 'item_id_fieldname', 'on_click', 'allow_clear'],
|
||||
props: ['item', 'item_id_fieldname', 'is_local', 'on_click', 'allow_clear'],
|
||||
computed: {
|
||||
title() {
|
||||
return this.item.item_name
|
||||
const item_name = this.item.item_name || this.item.name;
|
||||
return strip_html(item_name);
|
||||
},
|
||||
subtitle() {
|
||||
return comment_when(this.item.creation);
|
||||
const dot_spacer = '<span aria-hidden="true"> · </span>';
|
||||
if(this.is_local){
|
||||
return comment_when(this.item.creation);
|
||||
} else {
|
||||
let subtitle_items = [comment_when(this.item.creation)];
|
||||
const rating = this.item.average_rating;
|
||||
|
||||
if (rating > 0) {
|
||||
subtitle_items.push(rating + `<i class='fa fa-fw fa-star-o'></i>`)
|
||||
}
|
||||
|
||||
subtitle_items.push(this.item.company);
|
||||
|
||||
return subtitle_items.join(dot_spacer);
|
||||
}
|
||||
},
|
||||
item_id() {
|
||||
return this.item[this.item_id_fieldname];
|
||||
@ -58,6 +73,7 @@ export default {
|
||||
border: 1px solid @border-color;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover .hub-card-overlay {
|
||||
display: block;
|
||||
|
@ -12,6 +12,7 @@
|
||||
:key="item[item_id_fieldname]"
|
||||
:item="item"
|
||||
:item_id_fieldname="item_id_fieldname"
|
||||
:is_local="is_local"
|
||||
:on_click="on_click"
|
||||
:allow_clear="editable"
|
||||
@remove-item="$emit('remove-item', item[item_id_fieldname])"
|
||||
@ -29,6 +30,7 @@ export default {
|
||||
props: {
|
||||
items: Array,
|
||||
item_id_fieldname: String,
|
||||
is_local: Boolean,
|
||||
on_click: Function,
|
||||
editable: Boolean,
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
<item-cards-container
|
||||
:items="selected_items"
|
||||
:item_id_fieldname="item_id_fieldname"
|
||||
:is_local="true"
|
||||
:editable="true"
|
||||
@remove-item="remove_item_from_selection"
|
||||
|
||||
@ -44,6 +45,7 @@
|
||||
<item-cards-container
|
||||
:items="valid_items"
|
||||
:item_id_fieldname="item_id_fieldname"
|
||||
:is_local="true"
|
||||
:on_click="show_publishing_dialog_for_item"
|
||||
>
|
||||
</item-cards-container>
|
||||
|
120
erpnext/public/js/hub/components/SavedProductsPage.vue
Normal file
120
erpnext/public/js/hub/components/SavedProductsPage.vue
Normal file
@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div
|
||||
class="marketplace-page"
|
||||
:data-page-name="page_name"
|
||||
>
|
||||
<h5>{{ page_title }}</h5>
|
||||
|
||||
<item-cards-container
|
||||
:items="items"
|
||||
:item_id_fieldname="item_id_fieldname"
|
||||
:on_click="go_to_item_details_page"
|
||||
:editable="true"
|
||||
@remove-item="on_item_remove"
|
||||
:empty_state_message="empty_state_message"
|
||||
>
|
||||
</item-cards-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ItemCardsContainer from './ItemCardsContainer.vue';
|
||||
|
||||
export default {
|
||||
name: 'saved-products-page',
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
items: [],
|
||||
all_items: [],
|
||||
item_id_fieldname: 'hub_item_code',
|
||||
|
||||
// Constants
|
||||
page_title: __('Saved Products'),
|
||||
empty_state_message: __(`You haven't favourited any items yet.`)
|
||||
};
|
||||
},
|
||||
components: {
|
||||
ItemCardsContainer
|
||||
},
|
||||
created() {
|
||||
this.get_items();
|
||||
},
|
||||
methods: {
|
||||
get_items() {
|
||||
hub.call(
|
||||
'get_favourite_items_of_seller',
|
||||
{
|
||||
hub_seller: hub.settings.company_email
|
||||
},
|
||||
'action:item_favourite'
|
||||
)
|
||||
.then((items) => {
|
||||
this.items = items.map(item => {
|
||||
item.seen = true;
|
||||
return item;
|
||||
});
|
||||
})
|
||||
},
|
||||
|
||||
go_to_item_details_page(hub_item_code) {
|
||||
frappe.set_route(`marketplace/item/${hub_item_code}`);
|
||||
},
|
||||
|
||||
on_item_remove(hub_item_code) {
|
||||
const grace_period = 5000;
|
||||
let reverted = false;
|
||||
let alert;
|
||||
|
||||
const undo_remove = () => {
|
||||
this.toggle_item(hub_item_code);;
|
||||
reverted = true;
|
||||
alert.hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
alert = frappe.show_alert(__(`<span>${hub_item_code} removed.
|
||||
<a href="#" class="undo-remove" data-action="undo-remove"><b>Undo</b></a></span>`),
|
||||
grace_period/1000,
|
||||
{
|
||||
'undo-remove': undo_remove.bind(this)
|
||||
}
|
||||
);
|
||||
|
||||
this.toggle_item(hub_item_code, false);
|
||||
|
||||
setTimeout(() => {
|
||||
if(!reverted) {
|
||||
this.remove_item_from_saved_products(hub_item_code);
|
||||
}
|
||||
}, grace_period);
|
||||
},
|
||||
|
||||
remove_item_from_saved_products(hub_item_code) {
|
||||
erpnext.hub.trigger('action:item_favourite');
|
||||
hub.call('remove_item_from_seller_favourites', {
|
||||
hub_item_code,
|
||||
hub_seller: hub.settings.company_email
|
||||
})
|
||||
.then(() => {
|
||||
this.get_items();
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
},
|
||||
|
||||
// By default show
|
||||
toggle_item(hub_item_code, show=true) {
|
||||
this.items = this.items.map(item => {
|
||||
if(item.hub_item_code === hub_item_code) {
|
||||
item.seen = show;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -2,6 +2,7 @@ function get_item_card_html(item) {
|
||||
if (item.recent_message) {
|
||||
return get_item_message_card_html(item);
|
||||
}
|
||||
|
||||
const item_name = item.item_name || item.name;
|
||||
const title = strip_html(item_name);
|
||||
const img_url = item.image;
|
||||
@ -14,7 +15,7 @@ function get_item_card_html(item) {
|
||||
if (rating > 0) {
|
||||
subtitle.push(rating + `<i class='fa fa-fw fa-star-o'></i>`)
|
||||
}
|
||||
|
||||
|
||||
subtitle.push(company_name);
|
||||
|
||||
let dot_spacer = '<span aria-hidden="true"> · </span>';
|
||||
@ -51,61 +52,6 @@ function get_item_card_html(item) {
|
||||
return item_html;
|
||||
}
|
||||
|
||||
function get_local_item_card_html(item) {
|
||||
const item_name = item.item_name || item.name;
|
||||
const title = strip_html(item_name);
|
||||
const img_url = item.image;
|
||||
const company_name = item.company;
|
||||
|
||||
const is_active = item.publish_in_hub;
|
||||
const id = item.hub_item_code || item.item_code;
|
||||
|
||||
// Subtitle
|
||||
let subtitle = [comment_when(item.creation)];
|
||||
const rating = item.average_rating;
|
||||
|
||||
if (rating > 0) {
|
||||
subtitle.push(rating + `<i class='fa fa-fw fa-star-o'></i>`)
|
||||
}
|
||||
|
||||
if (company_name) {
|
||||
subtitle.push(company_name);
|
||||
}
|
||||
|
||||
let dot_spacer = '<span aria-hidden="true"> · </span>';
|
||||
subtitle = subtitle.join(dot_spacer);
|
||||
|
||||
const edit_item_button = `<div class="hub-card-overlay-button" style="right: 15px; bottom: 15px;" data-route="Form/Item/${item.item_name}">
|
||||
<button class="btn btn-default zoom-view">
|
||||
<i class="octicon octicon-pencil text-muted"></i>
|
||||
</button>
|
||||
</div>`;
|
||||
|
||||
const item_html = `
|
||||
<div class="col-md-3 col-sm-4 col-xs-6 hub-card-container">
|
||||
<div class="hub-card is-local ${is_active ? 'active' : ''}" data-id="${id}">
|
||||
<div class="hub-card-header flex">
|
||||
<div class="ellipsis">
|
||||
<div class="hub-card-title ellipsis bold">${title}</div>
|
||||
<div class="hub-card-subtitle ellipsis text-muted">${subtitle}</div>
|
||||
</div>
|
||||
<i class="octicon octicon-check text-success"></i>
|
||||
</div>
|
||||
<div class="hub-card-body">
|
||||
<img class="hub-card-image" src="${img_url}" />
|
||||
<div class="hub-card-overlay">
|
||||
<div class="hub-card-overlay-body">
|
||||
${edit_item_button}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return item_html;
|
||||
}
|
||||
|
||||
function get_item_message_card_html(item) {
|
||||
const item_name = item.item_name || item.name;
|
||||
const title = strip_html(item_name);
|
||||
@ -138,6 +84,5 @@ function get_item_message_card_html(item) {
|
||||
}
|
||||
|
||||
export {
|
||||
get_item_card_html,
|
||||
get_local_item_card_html
|
||||
get_item_card_html
|
||||
}
|
||||
|
@ -80,8 +80,8 @@ erpnext.hub.Marketplace = class Marketplace {
|
||||
$nav_group.empty();
|
||||
|
||||
const user_specific_items_html = this.registered
|
||||
? `<li class="hub-sidebar-item" data-route="marketplace/favourites">
|
||||
${__('Favorites')}
|
||||
? `<li class="hub-sidebar-item" data-route="marketplace/saved-products">
|
||||
${__('Saved Products')}
|
||||
</li>
|
||||
<li class="hub-sidebar-item text-muted" data-route="marketplace/profile">
|
||||
${__('Your Profile')}
|
||||
@ -196,8 +196,8 @@ erpnext.hub.Marketplace = class Marketplace {
|
||||
}
|
||||
|
||||
// registered seller routes
|
||||
if (route[1] === 'favourites' && !this.subpages.favourites) {
|
||||
this.subpages.favourites = new erpnext.hub.Favourites(this.$body);
|
||||
if (route[1] === 'saved-products' && !this.subpages['saved-products']) {
|
||||
this.subpages['saved-products'] = new erpnext.hub.SavedProducts(this.$body);
|
||||
}
|
||||
|
||||
if (route[1] === 'profile' && !this.subpages.profile) {
|
||||
@ -221,7 +221,7 @@ erpnext.hub.Marketplace = class Marketplace {
|
||||
}
|
||||
|
||||
// dont allow unregistered users to access registered routes
|
||||
const registered_routes = ['favourites', 'profile', 'publish', 'my-products', 'messages'];
|
||||
const registered_routes = ['saved-products', 'profile', 'publish', 'my-products', 'messages'];
|
||||
if (!hub.settings.registered && registered_routes.includes(route[1])) {
|
||||
frappe.set_route('marketplace', 'home');
|
||||
return;
|
||||
|
@ -1,82 +1,20 @@
|
||||
import SubPage from './subpage';
|
||||
import { get_item_card_container_html } from '../components/items_container';
|
||||
import SavedProductsPage from '../components/SavedProductsPage.vue';
|
||||
import Vue from 'vue/dist/vue.js';
|
||||
|
||||
erpnext.hub.Favourites = class Favourites extends SubPage {
|
||||
make_wrapper() {
|
||||
super.make_wrapper();
|
||||
this.bind_events();
|
||||
erpnext.hub.SavedProducts = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-saved">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(SavedProductsPage)
|
||||
}).$mount('#vue-area-saved');
|
||||
}
|
||||
|
||||
bind_events() {
|
||||
this.$wrapper.on('click', '.hub-card', (e) => {
|
||||
const $target = $(e.target);
|
||||
if($target.hasClass('octicon-x')) {
|
||||
e.stopPropagation();
|
||||
const hub_item_code = $target.attr('data-hub-item-code');
|
||||
this.on_item_remove(hub_item_code);
|
||||
}
|
||||
});
|
||||
show() {
|
||||
$('[data-page-name="saved-products"]').show();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.get_favourites()
|
||||
.then(items => {
|
||||
this.render(items);
|
||||
});
|
||||
hide() {
|
||||
$('[data-page-name="saved-products"]').hide();
|
||||
}
|
||||
|
||||
get_favourites() {
|
||||
return hub.call('get_favourite_items_of_seller', {
|
||||
hub_seller: hub.settings.company_email
|
||||
}, 'action:item_favourite');
|
||||
}
|
||||
|
||||
render(items) {
|
||||
this.$wrapper.find('.hub-items-container').empty();
|
||||
const html = get_item_card_container_html(items, __('Favourites'));
|
||||
this.$wrapper.html(html);
|
||||
this.$wrapper.find('.hub-card').addClass('closable');
|
||||
|
||||
if (!items.length) {
|
||||
this.render_empty_state();
|
||||
}
|
||||
}
|
||||
|
||||
render_empty_state() {
|
||||
this.$wrapper.find('.hub-items-container').append(`
|
||||
<div class="col-md-12">${__("You don't have any favourites yet.")}</div>
|
||||
`)
|
||||
}
|
||||
|
||||
on_item_remove(hub_item_code, $hub_card = '') {
|
||||
const $message = $(__(`<span>${hub_item_code} removed.
|
||||
<a href="#" data-action="undo-remove"><b>Undo</b></a></span>`));
|
||||
|
||||
frappe.show_alert($message);
|
||||
|
||||
$hub_card = this.$wrapper.find(`.hub-card[data-hub-item-code="${hub_item_code}"]`);
|
||||
|
||||
$hub_card.hide();
|
||||
|
||||
const grace_period = 5000;
|
||||
|
||||
setTimeout(() => {
|
||||
this.remove_item(hub_item_code, $hub_card);
|
||||
}, grace_period);
|
||||
}
|
||||
|
||||
remove_item(hub_item_code, $hub_card) {
|
||||
hub.call('remove_item_from_seller_favourites', {
|
||||
hub_item_code,
|
||||
hub_seller: hub.settings.company_email
|
||||
})
|
||||
.then(() => {
|
||||
$hub_card.remove();
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
|
||||
undo_remove(hub_item_code) { }
|
||||
}
|
||||
|
@ -44,18 +44,6 @@ body[data-route^="marketplace/"] {
|
||||
&:hover .hub-card-overlay {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.octicon-x {
|
||||
display: none;
|
||||
margin-left: 10px;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.hub-card.closable {
|
||||
.octicon-x {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.hub-card.is-local {
|
||||
|
Loading…
x
Reference in New Issue
Block a user