Merge branch 'hub-redesign' of https://github.com/frappe/erpnext into hub-redesign
This commit is contained in:
commit
ea82fb9f80
@ -1,34 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="app">
|
|
||||||
<hello></hello>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ItemCardsContainer from './components/ItemCardsContainer.vue';
|
|
||||||
export default {
|
|
||||||
name: 'app',
|
|
||||||
components: {
|
|
||||||
ItemCardsContainer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.app {
|
|
||||||
color: #444;
|
|
||||||
margin-top: 100px;
|
|
||||||
max-width: 600px;
|
|
||||||
font-family: Helvetica, sans-serif;
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
75
erpnext/public/js/hub/components/DetailView.vue
Normal file
75
erpnext/public/js/hub/components/DetailView.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="hub-item-container">
|
||||||
|
<div class="row visible-xs">
|
||||||
|
<div class="col-xs-12 margin-bottom">
|
||||||
|
<button class="btn btn-xs btn-default" data-route="marketplace/home">{{ back_to_home_text }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="show_skeleton" class="row margin-bottom">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="hub-item-skeleton-image"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 class="hub-skeleton" style="width: 75%;">Name</h2>
|
||||||
|
<div class="text-muted">
|
||||||
|
<p class="hub-skeleton" style="width: 35%;">Details</p>
|
||||||
|
<p class="hub-skeleton" style="width: 50%;">Ratings</p>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="hub-item-description">
|
||||||
|
<p class="hub-skeleton">Desc</p>
|
||||||
|
<p class="hub-skeleton" style="width: 85%;">Desc</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<div class="row margin-bottom">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="hub-item-image">
|
||||||
|
<img :src="image">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2>{{ title }}</h2>
|
||||||
|
<div class="text-muted">
|
||||||
|
<p v-for="subtitle in subtitles"
|
||||||
|
:key="subtitle"
|
||||||
|
v-html="subtitle"
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="section in sections" class="row hub-item-description margin-bottom"
|
||||||
|
:key="section.title"
|
||||||
|
>
|
||||||
|
<h6 class="col-md-12 margin-top">
|
||||||
|
<b class="text-muted">{{ section.title }}</b>
|
||||||
|
</h6>
|
||||||
|
<p class="col-md-12" v-html="section.content">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'detail-view',
|
||||||
|
props: ['title', 'subtitles', 'image', 'sections', 'show_skeleton'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
back_to_home_text: __('Back to Home')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
</style>
|
@ -4,6 +4,13 @@
|
|||||||
:style="{ height: height + 'px' }"
|
:style="{ height: height + 'px' }"
|
||||||
>
|
>
|
||||||
<p class="text-muted">{{ message }}</p>
|
<p class="text-muted">{{ message }}</p>
|
||||||
|
<p v-if="action">
|
||||||
|
<button class="btn btn-default btn-xs"
|
||||||
|
@click="action.on_click"
|
||||||
|
>
|
||||||
|
{{ action.label }}
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -15,7 +22,7 @@ export default {
|
|||||||
message: String,
|
message: String,
|
||||||
bordered: Boolean,
|
bordered: Boolean,
|
||||||
height: Number,
|
height: Number,
|
||||||
// action: Function
|
action: Object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
9
erpnext/public/js/hub/components/TimelineItem.vue
Normal file
9
erpnext/public/js/hub/components/TimelineItem.vue
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* Saving this for later */
|
||||||
|
<template>
|
||||||
|
<div class="media timeline-item notification-content">
|
||||||
|
<div class="small">
|
||||||
|
<i class="octicon octicon-bookmark fa-fw"></i>
|
||||||
|
<span title="Administrator"><b>4 weeks ago</b> Published 1 product to Marketplace</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -132,42 +132,6 @@ function get_detail_view_html(item, allow_edit) {
|
|||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_profile_html(profile) {
|
|
||||||
const p = profile;
|
|
||||||
const profile_html = `<div class="hub-item-container">
|
|
||||||
<div class="row visible-xs">
|
|
||||||
<div class="col-xs-12 margin-bottom">
|
|
||||||
<button class="btn btn-xs btn-default" data-route="marketplace/home">Back to home</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="hub-item-image">
|
|
||||||
<img src="${p.logo}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h2>${p.company}</h2>
|
|
||||||
<div class="text-muted">
|
|
||||||
<p>${p.country}</p>
|
|
||||||
<p>${p.site_name}</p>
|
|
||||||
<p>${__(`Joined ${comment_when(p.creation)}`)}</p>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="hub-item-description">
|
|
||||||
${'description'
|
|
||||||
? `<p>${p.company_description}</p>`
|
|
||||||
: `<p>__('No description')</p`
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
return profile_html;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
get_detail_view_html,
|
get_detail_view_html,
|
||||||
get_profile_html
|
get_profile_html
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
function get_empty_state(message, action) {
|
|
||||||
return `<div class="empty-state flex align-center flex-column justify-center">
|
|
||||||
<p class="text-muted">${message}</p>
|
|
||||||
${action ? `<p>${action}</p>`: ''}
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
get_empty_state
|
|
||||||
}
|
|
@ -1,108 +1,3 @@
|
|||||||
function get_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;
|
|
||||||
|
|
||||||
// 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>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
subtitle.push(company_name);
|
|
||||||
|
|
||||||
let dot_spacer = '<span aria-hidden="true"> · </span>';
|
|
||||||
subtitle = subtitle.join(dot_spacer);
|
|
||||||
|
|
||||||
// route
|
|
||||||
if (!item.route) {
|
|
||||||
item.route = `marketplace/item/${item.hub_item_code}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const item_html = `
|
|
||||||
<div class="col-md-3 col-sm-4 col-xs-6 hub-card-container">
|
|
||||||
<div class="hub-card"
|
|
||||||
data-hub-item-code="${item.hub_item_code}"
|
|
||||||
data-route="${item.route}">
|
|
||||||
|
|
||||||
<div class="hub-card-header level">
|
|
||||||
<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-x text-extra-muted"
|
|
||||||
data-hub-item-code="${item.hub_item_code}">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
<div class="hub-card-body">
|
|
||||||
<img class="hub-card-image" src="${img_url}" />
|
|
||||||
<div class="overlay hub-card-overlay"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
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" 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_buying_item_message_card_html(item) {
|
function get_buying_item_message_card_html(item) {
|
||||||
const item_name = item.item_name || item.name;
|
const item_name = item.item_name || item.name;
|
||||||
const title = strip_html(item_name);
|
const title = strip_html(item_name);
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import { get_item_card_html } from './item_card';
|
|
||||||
|
|
||||||
function get_item_card_container_html(items, title='', get_item_html = get_item_card_html, action='') {
|
|
||||||
const items_html = (items || []).map(item => get_item_html(item)).join('');
|
|
||||||
const title_html = title
|
|
||||||
? `<div class="hub-items-header flex">
|
|
||||||
<h4>${title}</h4>
|
|
||||||
${action}
|
|
||||||
</div>`
|
|
||||||
: '';
|
|
||||||
|
|
||||||
const html = `<div class="row hub-items-container">
|
|
||||||
${title_html}
|
|
||||||
${items_html}
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
get_item_card_container_html
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
function get_detail_skeleton_html() {
|
|
||||||
const skeleton = `<div class="hub-item-container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="hub-item-skeleton-image"></div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h2 class="hub-skeleton" style="width: 75%;">Name</h2>
|
|
||||||
<div class="text-muted">
|
|
||||||
<p class="hub-skeleton" style="width: 35%;">Details</p>
|
|
||||||
<p class="hub-skeleton" style="width: 50%;">Ratings</p>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="hub-item-description">
|
|
||||||
<p class="hub-skeleton">Desc</p>
|
|
||||||
<p class="hub-skeleton" style="width: 85%;">Desc</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
return skeleton;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
get_detail_skeleton_html
|
|
||||||
}
|
|
@ -3,11 +3,8 @@ import './vue-plugins';
|
|||||||
|
|
||||||
// pages
|
// pages
|
||||||
import './pages/item';
|
import './pages/item';
|
||||||
import './pages/seller';
|
|
||||||
import './pages/profile';
|
|
||||||
import './pages/messages';
|
import './pages/messages';
|
||||||
import './pages/buying_messages';
|
import './pages/buying_messages';
|
||||||
import './pages/not_found';
|
|
||||||
|
|
||||||
import PageContainer from './PageContainer.vue';
|
import PageContainer from './PageContainer.vue';
|
||||||
import Home from './pages/Home.vue';
|
import Home from './pages/Home.vue';
|
||||||
@ -16,6 +13,9 @@ import Publish from './pages/Publish.vue';
|
|||||||
import Category from './pages/Category.vue';
|
import Category from './pages/Category.vue';
|
||||||
import Search from './pages/Search.vue';
|
import Search from './pages/Search.vue';
|
||||||
import PublishedProducts from './pages/PublishedProducts.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
|
// components
|
||||||
import { ProfileDialog } from './components/profile_dialog';
|
import { ProfileDialog } from './components/profile_dialog';
|
||||||
@ -203,7 +203,7 @@ erpnext.hub.Marketplace = class Marketplace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (route[1] === 'seller' && !this.subpages['seller']) {
|
if (route[1] === 'seller' && !this.subpages['seller']) {
|
||||||
this.subpages['seller'] = new erpnext.hub.Seller(this.$body);
|
this.subpages['seller'] = new erpnext.hub.SellerPage(this.$body);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route[1] === 'register' && !this.subpages.register) {
|
if (route[1] === 'register' && !this.subpages.register) {
|
||||||
@ -220,7 +220,7 @@ erpnext.hub.Marketplace = class Marketplace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (route[1] === 'profile' && !this.subpages.profile) {
|
if (route[1] === 'profile' && !this.subpages.profile) {
|
||||||
this.subpages.profile = new erpnext.hub.Profile(this.$body);
|
this.subpages.profile = new erpnext.hub.ProfilePage(this.$body);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route[1] === 'publish' && !this.subpages.publish) {
|
if (route[1] === 'publish' && !this.subpages.publish) {
|
||||||
@ -248,7 +248,7 @@ erpnext.hub.Marketplace = class Marketplace {
|
|||||||
|
|
||||||
if (!Object.keys(this.subpages).includes(route[1])) {
|
if (!Object.keys(this.subpages).includes(route[1])) {
|
||||||
if (!this.subpages.not_found) {
|
if (!this.subpages.not_found) {
|
||||||
this.subpages.not_found = new erpnext.hub.NotFound(this.$body);
|
this.subpages.not_found = new erpnext.hub.NotFoundPage(this.$body);
|
||||||
}
|
}
|
||||||
route[1] = 'not_found';
|
route[1] = 'not_found';
|
||||||
}
|
}
|
||||||
@ -391,3 +391,58 @@ erpnext.hub.SearchPage = class {
|
|||||||
$('[data-page-name="search"]').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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
41
erpnext/public/js/hub/pages/NotFound.vue
Normal file
41
erpnext/public/js/hub/pages/NotFound.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="marketplace-page"
|
||||||
|
:data-page-name="page_name"
|
||||||
|
>
|
||||||
|
<empty-state
|
||||||
|
:message="empty_state_message"
|
||||||
|
:height="500"
|
||||||
|
:action="action"
|
||||||
|
>
|
||||||
|
</empty-state>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import EmptyState from '../components/EmptyState.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'not-found-page',
|
||||||
|
components: {
|
||||||
|
EmptyState
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
page_name: 'not-found',
|
||||||
|
action: {
|
||||||
|
label: __('Back to Home'),
|
||||||
|
on_click: () => {
|
||||||
|
frappe.set_route(`marketplace/home`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
empty_state_message: __(`Sorry! I could not find what you were looking for.`)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
73
erpnext/public/js/hub/pages/Profile.vue
Normal file
73
erpnext/public/js/hub/pages/Profile.vue
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="marketplace-page"
|
||||||
|
:data-page-name="page_name"
|
||||||
|
v-if="init || profile"
|
||||||
|
>
|
||||||
|
|
||||||
|
<detail-view
|
||||||
|
:title="title"
|
||||||
|
:subtitles="subtitles"
|
||||||
|
:image="image"
|
||||||
|
:sections="sections"
|
||||||
|
:show_skeleton="init"
|
||||||
|
>
|
||||||
|
</detail-view>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DetailView from '../components/DetailView.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'profile-page',
|
||||||
|
components: {
|
||||||
|
DetailView
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
page_name: frappe.get_route()[1],
|
||||||
|
|
||||||
|
init: true,
|
||||||
|
|
||||||
|
profile: null,
|
||||||
|
title: null,
|
||||||
|
subtitles: [],
|
||||||
|
image: null,
|
||||||
|
sections: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.get_profile();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
get_profile() {
|
||||||
|
hub.call(
|
||||||
|
'get_hub_seller_profile',
|
||||||
|
{ hub_seller: hub.settings.company_email }
|
||||||
|
).then(profile => {
|
||||||
|
this.init = false;
|
||||||
|
|
||||||
|
this.profile = profile;
|
||||||
|
this.title = profile.company;
|
||||||
|
this.subtitles = [
|
||||||
|
__(profile.country),
|
||||||
|
__(profile.site_name),
|
||||||
|
__(`Joined ${comment_when(profile.creation)}`)
|
||||||
|
];
|
||||||
|
this.image = profile.logo;
|
||||||
|
this.sections = [
|
||||||
|
{
|
||||||
|
title: __('About the Company'),
|
||||||
|
content: profile.company_description
|
||||||
|
? __(profile.company_description)
|
||||||
|
: __('No description')
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -71,7 +71,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
alert = frappe.show_alert(__(`<span>${hub_item_code} removed.
|
alert = frappe.show_alert(__(`<span>${hub_item_code} removed.
|
||||||
<a href="#" class="undo-remove" data-action="undo-remove"><b>Undo</b></a></span>`),
|
<a href="#" data-action="undo-remove"><b>Undo</b></a></span>`),
|
||||||
grace_period/1000,
|
grace_period/1000,
|
||||||
{
|
{
|
||||||
'undo-remove': undo_remove.bind(this)
|
'undo-remove': undo_remove.bind(this)
|
||||||
|
99
erpnext/public/js/hub/pages/Seller.vue
Normal file
99
erpnext/public/js/hub/pages/Seller.vue
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="marketplace-page"
|
||||||
|
:data-page-name="page_name"
|
||||||
|
v-if="init || profile"
|
||||||
|
>
|
||||||
|
<detail-view
|
||||||
|
:title="title"
|
||||||
|
:subtitles="subtitles"
|
||||||
|
:image="image"
|
||||||
|
:sections="sections"
|
||||||
|
:show_skeleton="init"
|
||||||
|
>
|
||||||
|
</detail-view>
|
||||||
|
|
||||||
|
<h5 v-if="profile">{{ item_container_heading }}</h5>
|
||||||
|
<item-cards-container
|
||||||
|
:container_name="item_container_heading"
|
||||||
|
:items="items"
|
||||||
|
:item_id_fieldname="item_id_fieldname"
|
||||||
|
:on_click="go_to_item_details_page"
|
||||||
|
>
|
||||||
|
</item-cards-container>
|
||||||
|
</div>
|
||||||
|
</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],
|
||||||
|
seller_company: frappe.get_route()[2],
|
||||||
|
|
||||||
|
init: true,
|
||||||
|
|
||||||
|
profile: null,
|
||||||
|
items:[],
|
||||||
|
item_id_fieldname: 'hub_item_code',
|
||||||
|
|
||||||
|
title: null,
|
||||||
|
subtitles: [],
|
||||||
|
image: null,
|
||||||
|
sections: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.get_seller_profile_and_items();
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
item_container_heading() {
|
||||||
|
return __('Products by ' + this.seller_company);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
get_seller_profile_and_items() {
|
||||||
|
hub.call(
|
||||||
|
'get_hub_seller_page_info',
|
||||||
|
{ company: this.seller_company }
|
||||||
|
).then(data => {
|
||||||
|
this.init = false;
|
||||||
|
this.profile = data.profile;
|
||||||
|
this.items = data.items;
|
||||||
|
|
||||||
|
const profile = this.profile;
|
||||||
|
|
||||||
|
this.title = profile.company;
|
||||||
|
this.subtitles = [
|
||||||
|
__(profile.country),
|
||||||
|
__(profile.site_name),
|
||||||
|
__(`Joined ${comment_when(profile.creation)}`)
|
||||||
|
];
|
||||||
|
this.image = profile.logo;
|
||||||
|
this.sections = [
|
||||||
|
{
|
||||||
|
title: __('About the Company'),
|
||||||
|
content: profile.company_description
|
||||||
|
? __(profile.company_description)
|
||||||
|
: __('No description')
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
go_to_item_details_page(hub_item_code) {
|
||||||
|
frappe.set_route(`marketplace/item/${hub_item_code}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -1,6 +1,6 @@
|
|||||||
import SubPage from './subpage';
|
import SubPage from './subpage';
|
||||||
import { get_detail_view_html } from '../components/detail_view';
|
import { get_detail_view_html } from '../components/detail_view';
|
||||||
import { get_detail_skeleton_html } from '../components/skeleton_state';
|
// import { get_detail_skeleton_html } from '../components/skeleton_state';
|
||||||
import { get_review_html } from '../components/reviews';
|
import { get_review_html } from '../components/reviews';
|
||||||
|
|
||||||
erpnext.hub.Item = class Item extends SubPage {
|
erpnext.hub.Item = class Item extends SubPage {
|
||||||
@ -20,7 +20,7 @@ erpnext.hub.Item = class Item extends SubPage {
|
|||||||
|
|
||||||
|
|
||||||
show_skeleton() {
|
show_skeleton() {
|
||||||
this.$wrapper.html(get_detail_skeleton_html());
|
// this.$wrapper.html(get_detail_skeleton_html());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import SubPage from './subpage';
|
import SubPage from './subpage';
|
||||||
import { get_item_card_container_html } from '../components/items_container';
|
// import { get_item_card_container_html } from '../components/items_container';
|
||||||
import { get_buying_item_message_card_html } from '../components/item_card';
|
import { get_buying_item_message_card_html } from '../components/item_card';
|
||||||
import { get_selling_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';
|
||||||
@ -22,7 +22,7 @@ erpnext.hub.Buying = class Buying extends SubPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(items = [], title) {
|
render(items = [], title) {
|
||||||
const html = get_item_card_container_html(items, title, get_buying_item_message_card_html);
|
// const html = get_item_card_container_html(items, title, get_buying_item_message_card_html);
|
||||||
this.$wrapper.append(html);
|
this.$wrapper.append(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ erpnext.hub.Selling = class Selling extends SubPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(items = [], title) {
|
render(items = [], title) {
|
||||||
const html = get_item_card_container_html(items, title, get_selling_item_message_card_html);
|
// const html = get_item_card_container_html(items, title, get_selling_item_message_card_html);
|
||||||
this.$wrapper.append(html);
|
this.$wrapper.append(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import SubPage from './subpage';
|
|
||||||
import { get_empty_state } from '../components/empty_state';
|
|
||||||
|
|
||||||
erpnext.hub.NotFound = class NotFound extends SubPage {
|
|
||||||
refresh() {
|
|
||||||
this.$wrapper.html(get_empty_state(
|
|
||||||
__('Sorry! I could not find what you were looking for.'),
|
|
||||||
`<button class="btn btn-default btn-xs" data-route="marketplace/home">${__('Back to home')}</button>`
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
import SubPage from './subpage';
|
|
||||||
import { get_detail_skeleton_html } from '../components/skeleton_state';
|
|
||||||
import { ProfileDialog } from '../components/profile_dialog';
|
|
||||||
|
|
||||||
erpnext.hub.Profile = class Profile extends SubPage {
|
|
||||||
make_wrapper() {
|
|
||||||
super.make_wrapper();
|
|
||||||
this.make_edit_profile_dialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh() {
|
|
||||||
this.show_skeleton();
|
|
||||||
this.get_hub_seller_profile(this.keyword)
|
|
||||||
.then(profile => {
|
|
||||||
this.edit_profile_dialog.set_values(profile);
|
|
||||||
this.render(profile);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get_hub_seller_profile() {
|
|
||||||
return hub.call('get_hub_seller_profile', { hub_seller: hub.settings.company_email });
|
|
||||||
}
|
|
||||||
|
|
||||||
show_skeleton() {
|
|
||||||
this.$wrapper.html(get_detail_skeleton_html());
|
|
||||||
}
|
|
||||||
|
|
||||||
render(profile) {
|
|
||||||
const p = profile;
|
|
||||||
const content_by_log_type = this.get_content_by_log_type();
|
|
||||||
|
|
||||||
let activity_logs = (p.hub_seller_activity || []).sort((a, b) => {
|
|
||||||
return new Date(b.creation) - new Date(a.creation);
|
|
||||||
});
|
|
||||||
|
|
||||||
const timeline_items_html = activity_logs
|
|
||||||
.map(log => {
|
|
||||||
const stats = JSON.parse(log.stats);
|
|
||||||
const no_of_items = stats && stats.push_update || '';
|
|
||||||
|
|
||||||
const content = content_by_log_type[log.type];
|
|
||||||
const message = content.get_message(no_of_items);
|
|
||||||
const icon = content.icon;
|
|
||||||
return this.get_timeline_log_item(log.pretty_date, message, icon);
|
|
||||||
})
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
const profile_html = `<div class="hub-item-container">
|
|
||||||
<div class="row visible-xs">
|
|
||||||
<div class="col-xs-12 margin-bottom">
|
|
||||||
<button class="btn btn-xs btn-default" data-route="marketplace/home">Back to home</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="hub-item-image">
|
|
||||||
<img src="${p.logo}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<h2>${p.company}</h2>
|
|
||||||
<div class="text-muted">
|
|
||||||
<p>${p.country}</p>
|
|
||||||
<p>${p.site_name}</p>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="hub-item-description">
|
|
||||||
${'description'
|
|
||||||
? `<p>${p.company_description}</p>`
|
|
||||||
: `<p>__('No description')</p`
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div 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><a data-action="edit_profile">${__('Edit Profile')}</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="timeline">
|
|
||||||
<div class="timeline-items">
|
|
||||||
${timeline_items_html}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
this.$wrapper.html(profile_html);
|
|
||||||
}
|
|
||||||
|
|
||||||
make_edit_profile_dialog() {
|
|
||||||
this.edit_profile_dialog = ProfileDialog(
|
|
||||||
__('Edit Profile'),
|
|
||||||
{
|
|
||||||
label: __('Update'),
|
|
||||||
on_submit: this.update_profile.bind(this)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
this.edit_profile_dialog.set_df_property('company_email', 'read_only', 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
edit_profile() {
|
|
||||||
this.edit_profile_dialog.set_values({
|
|
||||||
company_email: hub.settings.company_email
|
|
||||||
});
|
|
||||||
this.edit_profile_dialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
update_profile(new_values) {
|
|
||||||
hub.call('update_profile', {
|
|
||||||
hub_seller: hub.settings.company_email,
|
|
||||||
updated_profile: new_values
|
|
||||||
}).then(new_profile => {
|
|
||||||
this.edit_profile_dialog.hide();
|
|
||||||
this.render(new_profile);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get_timeline_log_item(pretty_date, message, icon) {
|
|
||||||
return `<div class="media timeline-item notification-content">
|
|
||||||
<div class="small">
|
|
||||||
<i class="octicon ${icon} fa-fw"></i>
|
|
||||||
<span title="Administrator"><b>${pretty_date}</b> ${message}</span>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_content_by_log_type() {
|
|
||||||
return {
|
|
||||||
"Created": {
|
|
||||||
icon: 'octicon-heart',
|
|
||||||
get_message: () => 'Joined Marketplace'
|
|
||||||
},
|
|
||||||
"Items Publish": {
|
|
||||||
icon: 'octicon-bookmark',
|
|
||||||
get_message: (no_of_items) =>
|
|
||||||
`Published ${no_of_items} product${no_of_items > 1 ? 's' : ''} to Marketplace`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
import SubPage from './subpage';
|
|
||||||
import { get_profile_html } from '../components/detail_view';
|
|
||||||
import { get_item_card_container_html } from '../components/items_container';
|
|
||||||
import { get_detail_skeleton_html } from '../components/skeleton_state';
|
|
||||||
|
|
||||||
erpnext.hub.Seller = class Seller extends SubPage {
|
|
||||||
make_wrapper() {
|
|
||||||
super.make_wrapper();
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh() {
|
|
||||||
this.show_skeleton();
|
|
||||||
this.company = frappe.get_route()[2];
|
|
||||||
this.get_hub_seller_profile()
|
|
||||||
.then(this.render.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
get_hub_seller_profile() {
|
|
||||||
return hub.call('get_hub_seller_page_info', { company: this.company });
|
|
||||||
}
|
|
||||||
|
|
||||||
show_skeleton() {
|
|
||||||
this.$wrapper.html(get_detail_skeleton_html());
|
|
||||||
}
|
|
||||||
|
|
||||||
render(data) {
|
|
||||||
this.$wrapper.html(get_profile_html(data.profile));
|
|
||||||
|
|
||||||
let html = get_item_card_container_html(data.items, __('Products by ' + p.company));
|
|
||||||
this.$wrapper.append(html);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user