[hub] Register components, init Item Page
- commonly used components are pre-registered - add DetailHeaderItem component - begin ItemPage
This commit is contained in:
parent
ea82fb9f80
commit
d0a952bcda
@ -3,25 +3,37 @@
|
||||
<component :is="current_page"></component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import Home from './pages/Home.vue';
|
||||
import SavedProducts from './pages/SavedProducts.vue';
|
||||
import Publish from './pages/Publish.vue';
|
||||
import Category from './pages/Category.vue';
|
||||
import Search from './pages/Search.vue';
|
||||
import Category from './pages/Category.vue';
|
||||
import SavedProducts from './pages/SavedProducts.vue';
|
||||
import PublishedProducts from './pages/PublishedProducts.vue';
|
||||
import Item from './pages/Item.vue';
|
||||
import Seller from './pages/Seller.vue';
|
||||
import Publish from './pages/Publish.vue';
|
||||
import Buying from './pages/Buying.vue';
|
||||
import BuyingMessages from './pages/BuyingMessages.vue';
|
||||
import Profile from './pages/Profile.vue';
|
||||
import NotFound from './pages/NotFound.vue';
|
||||
|
||||
const route_map = {
|
||||
'marketplace/home': Home,
|
||||
'marketplace/saved-products': SavedProducts,
|
||||
'marketplace/my-products': PublishedProducts,
|
||||
'marketplace/publish': Publish,
|
||||
'marketplace/category/:category': Category,
|
||||
'marketplace/search/:keyword': Search,
|
||||
'marketplace/category/:category': Category,
|
||||
'marketplace/item/:item': Item,
|
||||
'marketplace/seller/:seller': Seller,
|
||||
'marketplace/not-found': NotFound,
|
||||
|
||||
// Registered seller routes
|
||||
'marketplace/profile': Profile,
|
||||
'marketplace/saved-products': SavedProducts,
|
||||
'marketplace/publish': Publish,
|
||||
'marketplace/my-products': PublishedProducts,
|
||||
'marketplace/buying': Buying,
|
||||
'marketplace/buying/:item': BuyingMessages
|
||||
'marketplace/buying/:item': BuyingMessages,
|
||||
}
|
||||
|
||||
export default {
|
||||
|
20
erpnext/public/js/hub/components/DetailHeaderItem.vue
Normal file
20
erpnext/public/js/hub/components/DetailHeaderItem.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<p class="text-muted" v-html="header_item"></p>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
const spacer = '<span aria-hidden="true"> · </span>';
|
||||
|
||||
export default {
|
||||
name: 'header-item',
|
||||
props: ['value'],
|
||||
data() {
|
||||
return {
|
||||
header_item: Array.isArray(this.value)
|
||||
? this.value.join(spacer)
|
||||
: this.value
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
@ -31,16 +31,31 @@
|
||||
<img :src="image">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-8">
|
||||
<h2>{{ title }}</h2>
|
||||
<div class="text-muted">
|
||||
<p v-for="subtitle in subtitles"
|
||||
:key="subtitle"
|
||||
v-html="subtitle"
|
||||
>
|
||||
</p>
|
||||
<slot name="subtitle"></slot>
|
||||
</div>
|
||||
|
||||
<button v-if="primary_action" class="btn btn-primary" @click="primary_action.action">
|
||||
{{ primary_action.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="menu_items" class="col-md-1">
|
||||
<div class="dropdown pull-right hub-item-dropdown">
|
||||
<a class="dropdown-toggle btn btn-xs btn-default" data-toggle="dropdown">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-right" role="menu">
|
||||
<li v-for="menu_item in menu_items"
|
||||
v-if="menu_item.condition"
|
||||
:key="menu_item.label"
|
||||
>
|
||||
<a @click="menu_item.action">{{ menu_item.label }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="section in sections" class="row hub-item-description margin-bottom"
|
||||
@ -61,7 +76,7 @@
|
||||
|
||||
export default {
|
||||
name: 'detail-view',
|
||||
props: ['title', 'subtitles', 'image', 'sections', 'show_skeleton'],
|
||||
props: ['title', 'subtitles', 'image', 'sections', 'show_skeleton', 'menu_items', 'primary_action'],
|
||||
data() {
|
||||
return {
|
||||
back_to_home_text: __('Back to Home')
|
||||
|
@ -2,20 +2,10 @@ import Vue from 'vue/dist/vue.js';
|
||||
import './vue-plugins';
|
||||
|
||||
// pages
|
||||
import './pages/item';
|
||||
import './pages/messages';
|
||||
import './pages/buying_messages';
|
||||
|
||||
import PageContainer from './PageContainer.vue';
|
||||
import Home from './pages/Home.vue';
|
||||
import SavedProducts from './pages/SavedProducts.vue';
|
||||
import Publish from './pages/Publish.vue';
|
||||
import Category from './pages/Category.vue';
|
||||
import Search from './pages/Search.vue';
|
||||
import PublishedProducts from './pages/PublishedProducts.vue';
|
||||
import Profile from './pages/Profile.vue';
|
||||
import Seller from './pages/Seller.vue';
|
||||
import NotFound from './pages/NotFound.vue';
|
||||
|
||||
// components
|
||||
import { ProfileDialog } from './components/profile_dialog';
|
||||
@ -199,7 +189,7 @@ erpnext.hub.Marketplace = class Marketplace {
|
||||
}
|
||||
|
||||
if (route[1] === 'item' && route[2] && !this.subpages.item) {
|
||||
this.subpages.item = new erpnext.hub.Item(this.$body);
|
||||
this.subpages.item = new erpnext.hub.ItemPage(this.$body);
|
||||
}
|
||||
|
||||
if (route[1] === 'seller' && !this.subpages['seller']) {
|
||||
@ -282,167 +272,3 @@ erpnext.hub.Marketplace = class Marketplace {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.HomePage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-home">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(Home)
|
||||
}).$mount('#vue-area-home');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="home"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="home"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.SavedProductsPage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-saved">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(SavedProducts)
|
||||
}).$mount('#vue-area-saved');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="saved-products"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="saved-products"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.PublishPage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(Publish)
|
||||
}).$mount('#vue-area');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="publish"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="publish"]').hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
erpnext.hub.CategoryPage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-category">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(Category)
|
||||
}).$mount('#vue-area-category');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="category"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="category"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.PublishedProductsPage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-published-products">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(PublishedProducts)
|
||||
}).$mount('#vue-area-published-products');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="published-products"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="published-products"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.SearchPage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-search">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(Search)
|
||||
}).$mount('#vue-area-search');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="search"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="search"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.ProfilePage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-profile">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(Profile)
|
||||
}).$mount('#vue-area-profile');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="profile"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="profile"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.SellerPage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-seller">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(Seller)
|
||||
}).$mount('#vue-area-seller');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="seller"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="seller"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.NotFoundPage = class {
|
||||
constructor(parent) {
|
||||
this.$wrapper = $(`<div id="vue-area-not-found">`).appendTo($(parent));
|
||||
|
||||
new Vue({
|
||||
render: h => h(NotFound)
|
||||
}).$mount('#vue-area-not-found');
|
||||
}
|
||||
|
||||
show() {
|
||||
$('[data-page-name="not-found"]').show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$('[data-page-name="not-found"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ItemCardsContainer from '../components/ItemCardsContainer.vue';
|
||||
|
||||
export default {
|
||||
name: 'saved-products-page',
|
||||
components: {
|
||||
ItemCardsContainer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
|
@ -27,17 +27,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SearchInput from '../components/SearchInput.vue';
|
||||
import SectionHeader from '../components/SectionHeader.vue';
|
||||
import ItemCardsContainer from '../components/ItemCardsContainer.vue';
|
||||
|
||||
export default {
|
||||
name: 'home-page',
|
||||
components: {
|
||||
SectionHeader,
|
||||
SearchInput,
|
||||
ItemCardsContainer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
|
150
erpnext/public/js/hub/pages/Item.vue
Normal file
150
erpnext/public/js/hub/pages/Item.vue
Normal file
@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div
|
||||
class="marketplace-page"
|
||||
:data-page-name="page_name"
|
||||
v-if="init || item"
|
||||
>
|
||||
|
||||
<detail-view
|
||||
:title="title"
|
||||
:subtitles="subtitles"
|
||||
:image="image"
|
||||
:sections="sections"
|
||||
:menu_items="menu_items"
|
||||
:show_skeleton="init"
|
||||
>
|
||||
<detail-header-item slot="subtitle"
|
||||
:value="item_subtitle"
|
||||
></detail-header-item>
|
||||
<detail-header-item slot="subtitle"
|
||||
:value="item_views_and_ratings"
|
||||
></detail-header-item>
|
||||
</detail-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get_rating_html } from '../components/reviews';
|
||||
|
||||
export default {
|
||||
name: 'item-page',
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
hub_item_code: frappe.get_route()[2],
|
||||
|
||||
init: true,
|
||||
|
||||
item: null,
|
||||
title: null,
|
||||
subtitles: [],
|
||||
image: null,
|
||||
sections: [],
|
||||
|
||||
menu_items: [
|
||||
{
|
||||
label: __('Report this Product'),
|
||||
condition: !this.is_own_item,
|
||||
action: this.report_item
|
||||
},
|
||||
{
|
||||
label: __('Edit Details'),
|
||||
condition: this.is_own_item,
|
||||
action: this.report_item
|
||||
},
|
||||
{
|
||||
label: __('Unpublish Product'),
|
||||
condition: this.is_own_item,
|
||||
action: this.report_item
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
is_own_item() {
|
||||
let is_own_item = false;
|
||||
if(this.item) {
|
||||
if(this.item.hub_seller === hub.setting.company_email) {
|
||||
is_own_item = true;
|
||||
}
|
||||
}
|
||||
return is_own_item;
|
||||
},
|
||||
|
||||
item_subtitle() {
|
||||
if(!this.item) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const dot_spacer = '<span aria-hidden="true"> · </span>';
|
||||
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;
|
||||
},
|
||||
|
||||
item_views_and_ratings() {
|
||||
if(!this.item) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let stats = __('No views yet');
|
||||
if(this.item.view_count) {
|
||||
const views_message = __(`${this.item.view_count} Views`);
|
||||
|
||||
const rating_html = get_rating_html(this.item.average_rating);
|
||||
const rating_count = this.item.no_of_ratings > 0 ? `${this.item.no_of_ratings} reviews` : __('No reviews yet');
|
||||
|
||||
stats = [views_message, rating_html, rating_count];
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.get_profile();
|
||||
},
|
||||
methods: {
|
||||
get_profile() {
|
||||
hub.call('get_item_details',{ hub_item_code: this.hub_item_code })
|
||||
.then(item => {
|
||||
this.init = false;
|
||||
this.item = item;
|
||||
|
||||
this.build_data();
|
||||
});
|
||||
},
|
||||
|
||||
build_data() {
|
||||
this.title = this.item.item_name || this.item.name;
|
||||
|
||||
this.image = this.item.image;
|
||||
|
||||
this.sections = [
|
||||
{
|
||||
title: __('Product Description'),
|
||||
content: this.item.description
|
||||
? __(this.item.description)
|
||||
: __('No description')
|
||||
},
|
||||
{
|
||||
title: __('Seller Information'),
|
||||
content: ''
|
||||
}
|
||||
];
|
||||
},
|
||||
|
||||
report_item(){
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -14,13 +14,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyState from '../components/EmptyState.vue';
|
||||
|
||||
export default {
|
||||
name: 'not-found-page',
|
||||
components: {
|
||||
EmptyState
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page_name: 'not-found',
|
||||
|
@ -17,13 +17,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DetailView from '../components/DetailView.vue';
|
||||
|
||||
export default {
|
||||
name: 'profile-page',
|
||||
components: {
|
||||
DetailView
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
|
@ -54,13 +54,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SearchInput from '../components/SearchInput.vue';
|
||||
import ItemCardsContainer from '../components/ItemCardsContainer.vue';
|
||||
import NotificationMessage from '../components/NotificationMessage.vue';
|
||||
import { ItemPublishDialog } from '../components/item_publish_dialog';
|
||||
|
||||
export default {
|
||||
name: 'publish-page',
|
||||
components: {
|
||||
NotificationMessage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
@ -87,11 +88,6 @@ export default {
|
||||
: ''
|
||||
};
|
||||
},
|
||||
components: {
|
||||
SearchInput,
|
||||
ItemCardsContainer,
|
||||
NotificationMessage
|
||||
},
|
||||
computed: {
|
||||
no_selected_items() {
|
||||
return this.selected_items.length === 0;
|
||||
|
@ -17,13 +17,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ItemCardsContainer from '../components/ItemCardsContainer.vue';
|
||||
|
||||
export default {
|
||||
name: 'saved-products-page',
|
||||
components: {
|
||||
ItemCardsContainer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
|
@ -19,8 +19,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ItemCardsContainer from '../components/ItemCardsContainer.vue';
|
||||
|
||||
export default {
|
||||
name: 'saved-products-page',
|
||||
data() {
|
||||
@ -34,9 +32,6 @@ export default {
|
||||
empty_state_message: __(`You haven't favourited any items yet.`)
|
||||
};
|
||||
},
|
||||
components: {
|
||||
ItemCardsContainer
|
||||
},
|
||||
created() {
|
||||
this.get_items();
|
||||
},
|
||||
|
@ -24,15 +24,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SearchInput from '../components/SearchInput.vue';
|
||||
import ItemCardsContainer from '../components/ItemCardsContainer.vue';
|
||||
|
||||
export default {
|
||||
name: 'saved-products-page',
|
||||
components: {
|
||||
SearchInput,
|
||||
ItemCardsContainer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
|
@ -25,15 +25,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DetailView from '../components/DetailView.vue';
|
||||
import ItemCardsContainer from '../components/ItemCardsContainer.vue';
|
||||
|
||||
export default {
|
||||
name: 'seller-page',
|
||||
components: {
|
||||
DetailView,
|
||||
ItemCardsContainer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page_name: frappe.get_route()[1],
|
||||
|
@ -2,7 +2,7 @@ import SubPage from './subpage';
|
||||
// import { get_item_card_container_html } from '../components/items_container';
|
||||
import { get_buying_item_message_card_html } from '../components/item_card';
|
||||
import { get_selling_item_message_card_html } from '../components/item_card';
|
||||
import { get_empty_state } from '../components/empty_state';
|
||||
// import { get_empty_state } from '../components/empty_state';
|
||||
|
||||
erpnext.hub.Buying = class Buying extends SubPage {
|
||||
refresh() {
|
||||
@ -27,8 +27,8 @@ erpnext.hub.Buying = class Buying extends SubPage {
|
||||
}
|
||||
|
||||
render_empty_state() {
|
||||
const empty_state = get_empty_state(__('You haven\'t interacted with any seller yet.'));
|
||||
this.$wrapper.html(empty_state);
|
||||
// const empty_state = get_empty_state(__('You haven\'t interacted with any seller yet.'));
|
||||
// this.$wrapper.html(empty_state);
|
||||
}
|
||||
|
||||
get_items_for_messages() {
|
||||
|
@ -1,7 +1,23 @@
|
||||
import Vue from 'vue/dist/vue.js';
|
||||
|
||||
// Global components
|
||||
import ItemCardsContainer from './components/ItemCardsContainer.vue';
|
||||
import SectionHeader from './components/SectionHeader.vue';
|
||||
import SearchInput from './components/SearchInput.vue';
|
||||
import DetailView from './components/DetailView.vue';
|
||||
import DetailHeaderItem from './components/DetailHeaderItem.vue';
|
||||
import EmptyState from './components/EmptyState.vue';
|
||||
|
||||
Vue.prototype.__ = window.__;
|
||||
Vue.prototype.frappe = window.frappe;
|
||||
|
||||
Vue.component('item-cards-container', ItemCardsContainer);
|
||||
Vue.component('section-header', SectionHeader);
|
||||
Vue.component('search-input', SearchInput);
|
||||
Vue.component('detail-view', DetailView);
|
||||
Vue.component('detail-header-item', DetailHeaderItem);
|
||||
Vue.component('empty-state', EmptyState);
|
||||
|
||||
Vue.directive('route', {
|
||||
bind(el, binding) {
|
||||
const route = binding.value;
|
||||
|
Loading…
x
Reference in New Issue
Block a user