[hub][vue] add empty state and dynamic publish button
diff --git a/erpnext/public/js/hub/components/EmptyState.vue b/erpnext/public/js/hub/components/EmptyState.vue
new file mode 100644
index 0000000..3e0cb0e
--- /dev/null
+++ b/erpnext/public/js/hub/components/EmptyState.vue
@@ -0,0 +1,23 @@
+<template>
+ <div class="empty-state flex align-center flex-column justify-center"
+ :class="{ bordered: bordered }"
+ :style="{ height: height + 'px' }"
+ >
+ <p class="text-muted">{{ message }}</p>
+ </div>
+</template>
+
+<script>
+
+export default {
+ name: 'empty-state',
+ props: {
+ message: String,
+ bordered: Boolean,
+ height: Number,
+ // action: Function
+ }
+}
+</script>
+
+<style scoped></style>
diff --git a/erpnext/public/js/hub/components/ItemCardsContainer.vue b/erpnext/public/js/hub/components/ItemCardsContainer.vue
index 4ccb9dc..01fd01e 100644
--- a/erpnext/public/js/hub/components/ItemCardsContainer.vue
+++ b/erpnext/public/js/hub/components/ItemCardsContainer.vue
@@ -1,5 +1,12 @@
<template>
<div>
+ <empty-state
+ v-if="items.length === 0"
+ :message="empty_state_message"
+ :bordered="true"
+ :height="80"
+ >
+ </empty-state>
<item-card
v-for="item in items"
:key="item[item_id]"
@@ -12,12 +19,21 @@
<script>
import ItemCard from './ItemCard.vue';
+import EmptyState from './EmptyState.vue';
export default {
name: 'item-cards-container',
- props: ['items', 'is_local'],
+ props: {
+ 'items': Array,
+ 'is_local': Boolean,
+
+ 'empty_state_message': String,
+ 'empty_state_height': Number,
+ 'empty_state_bordered': Boolean
+ },
components: {
- ItemCard
+ ItemCard,
+ EmptyState
},
computed: {
item_id() {
diff --git a/erpnext/public/js/hub/components/NotificationMessage.vue b/erpnext/public/js/hub/components/NotificationMessage.vue
new file mode 100644
index 0000000..c77f15e
--- /dev/null
+++ b/erpnext/public/js/hub/components/NotificationMessage.vue
@@ -0,0 +1,20 @@
+<template>
+ <div class="subpage-message">
+ <p class="text-muted flex">
+ <span v-html="message"></span>
+ <i class="octicon octicon-x text-extra-muted"></i>
+ </p>
+ </div>
+</template>
+
+<script>
+
+export default {
+ name: ' notification-message',
+ props: {
+ message: String,
+ }
+}
+</script>
+
+<style scoped></style>
diff --git a/erpnext/public/js/hub/components/PublishPage.vue b/erpnext/public/js/hub/components/PublishPage.vue
index 2b2956f..670f010 100644
--- a/erpnext/public/js/hub/components/PublishPage.vue
+++ b/erpnext/public/js/hub/components/PublishPage.vue
@@ -3,15 +3,36 @@
class="marketplace-page"
:data-page-name="page_name"
>
+ <div class="flex justify-between align-flex-end">
+ <h5>{{ page_title }}</h5>
+
+ <button class="btn btn-primary btn-sm publish-items"
+ :disabled="no_selected_items">
+ <span>{{ publish_button_text }}</span>
+ </button>
+ </div>
+
+ <item-cards-container
+ :items="selected_items"
+ :is_local="true"
+ :empty_state_message="empty_state_message"
+ :empty_state_bordered="true"
+ :empty_state_height="80"
+ >
+ </item-cards-container>
+
+ <p class="text-muted">{{ valid_products_instruction }}</p>
+
<search-input
- placeholder="Search Items ..."
+ :placeholder="search_placeholder"
:on_search="get_valid_items"
v-model="search_value"
>
</search-input>
+
<item-cards-container
:items="valid_items"
- :is_local="1"
+ :is_local="true"
>
</item-cards-container>
</div>
@@ -27,13 +48,40 @@
return {
page_name: frappe.get_route()[1],
valid_items: [],
- search_value: ''
+ selected_items: [],
+ search_value: '',
+
+ // Constants
+ page_title: __('Publish Products'),
+ search_placeholder: __('Search Items ...'),
+ empty_state_message: __(`No Items selected yet.
+ Browse and click on products below to publish.`),
+ valid_products_instruction: __(`Only products with an image, description
+ and category can be published. Please update them if an item in your
+ inventory does not appear.`)
};
},
components: {
SearchInput,
ItemCardsContainer
},
+ computed: {
+ no_selected_items() {
+ return this.selected_items.length === 0;
+ },
+
+ publish_button_text() {
+ const number = this.selected_items.length;
+ let text = 'Publish';
+ if(number === 1) {
+ text = 'Publish 1 Product';
+ }
+ if(number > 1) {
+ text = `Publish ${number} Products`;
+ }
+ return __(text);
+ }
+ },
created() {
this.get_valid_items();
},
diff --git a/erpnext/public/js/hub/pages/publish.js b/erpnext/public/js/hub/pages/publish.js
index 7b20907..78ca58d 100644
--- a/erpnext/public/js/hub/pages/publish.js
+++ b/erpnext/public/js/hub/pages/publish.js
@@ -4,6 +4,8 @@
import { make_search_bar } from '../components/search_bar';
import { get_publishing_header } from '../components/publishing_area';
import { ItemPublishDialog } from '../components/item_publish_dialog';
+
+
import PublishPage from '../components/PublishPage.vue';
erpnext.hub.Publish = class Publish {
diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less
index 5f497d9..71e9534 100644
--- a/erpnext/public/less/hub.less
+++ b/erpnext/public/less/hub.less
@@ -213,14 +213,13 @@
.empty-state {
height: 500px;
+ margin: 15px 0px;
}
- .empty-items-container {
- height: 80px;
+ .empty-state.bordered {
border-radius: 4px;
border: 1px solid @border-color;
border-style: dashed;
- margin: 15px 0px;
}
.publish-area.filled {