[hub] Merge conflicts
diff --git a/erpnext/public/js/hub/components/Rating.vue b/erpnext/public/js/hub/components/Rating.vue
new file mode 100644
index 0000000..33290b8
--- /dev/null
+++ b/erpnext/public/js/hub/components/Rating.vue
@@ -0,0 +1,16 @@
+<template>
+    <span>
+        <i v-for="index in max_rating"
+            :key="index"
+            class="fa fa-fw star-icon"
+            :class="{'fa-star': index <= rating, 'fa-star-o': index > rating}"
+        >
+        </i>
+    </span>
+</template>
+
+<script>
+export default {
+    props: ['rating', 'max_rating']
+}
+</script>
diff --git a/erpnext/public/js/hub/components/ReviewArea.vue b/erpnext/public/js/hub/components/ReviewArea.vue
index 64057cd..070d0a6 100644
--- a/erpnext/public/js/hub/components/ReviewArea.vue
+++ b/erpnext/public/js/hub/components/ReviewArea.vue
@@ -1,15 +1,52 @@
 <template>
 	<div>
 		<div ref="review-area" class="timeline-head"></div>
+		<div class="timeline-items">
+			<review-timeline-item v-for="review in reviews"
+				:key="review.user"
+				:username="review.username"
+				:avatar="review.user_image"
+				:comment_when="when(review.modified)"
+				:rating="review.rating"
+				:subject="review.subject"
+				:content="review.content"
+			>
+			</review-timeline-item>
+		</div>
 	</div>
 </template>
 <script>
+import ReviewTimelineItem from '../components/ReviewTimelineItem.vue';
+
 export default {
-	props: ['hub_item_code'],
+	props: ['hub_item_name'],
+	data() {
+		return {
+			reviews: []
+		}
+	},
+	components: {
+		ReviewTimelineItem
+	},
+	created() {
+		this.get_item_reviews();
+	},
 	mounted() {
 		this.make_input();
 	},
 	methods: {
+		when(datetime) {
+			return comment_when(datetime);
+		},
+
+		get_item_reviews() {
+			hub.call('get_item_reviews', { hub_item_name: this.hub_item_name })
+				.then(reviews => {
+					this.reviews = reviews;
+				})
+				.catch(() => {});
+		},
+
 		make_input() {
 			this.review_area = new frappe.ui.ReviewArea({
 				parent: this.$refs['review-area'],
@@ -19,17 +56,19 @@
 		},
 
 		on_submit_review(values) {
-			values.user = frappe.session.user;
-			values.username = frappe.session.user_fullname;
+			values.user = hub.settings.company_email;
 
 			this.review_area.reset();
-			this.$emit('change', message);
 
 			hub.call('add_item_review', {
-				hub_item_code: this.hub_item_code,
+				hub_item_name: this.hub_item_name,
 				review: JSON.stringify(values)
 			})
-			// .then(this.push_review_in_review_area.bind(this));
+			.then(this.push_review.bind(this));
+		},
+
+		push_review(review){
+			this.reviews.unshift(review);
 		}
 	}
 }
diff --git a/erpnext/public/js/hub/components/ReviewTimelineItem.vue b/erpnext/public/js/hub/components/ReviewTimelineItem.vue
index e69de29..f0fe001 100644
--- a/erpnext/public/js/hub/components/ReviewTimelineItem.vue
+++ b/erpnext/public/js/hub/components/ReviewTimelineItem.vue
@@ -0,0 +1,54 @@
+<template>
+    <div class="media timeline-item user-content" data-doctype="${''}" data-name="${''}">
+		<span class="pull-left avatar avatar-medium hidden-xs" style="margin-top: 1px">
+			<!-- ${image_html} -->
+		</span>
+		<div class="pull-left media-body">
+			<div class="media-content-wrapper">
+				<div class="action-btns">
+                    <!-- ${edit_html} -->
+                </div>
+
+				<div class="comment-header clearfix">
+					<span class="pull-left avatar avatar-small visible-xs">
+						<!-- ${image_html} -->
+					</span>
+
+					<div class="asset-details">
+						<span class="author-wrap">
+							<i class="octicon octicon-quote hidden-xs fa-fw"></i>
+							<span>
+                                {{ username }}
+                            </span>
+						</span>
+						<a class="text-muted">
+							<span class="text-muted hidden-xs">&ndash;</span>
+							<span class="hidden-xs" v-html="comment_when"></span>
+						</a>
+					</div>
+				</div>
+				<div class="reply timeline-content-show">
+					<div class="timeline-item-content">
+						<p class="text-muted">
+							<rating :rating="rating" :max_rating="5"></rating>
+						</p>
+						<h6 class="bold">{{ subject }}</h6>
+						<p class="text-muted" v-html="content"></p>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+import Rating from '../components/Rating.vue';
+
+export default {
+    props: ['username', 'comment_when', 'avatar', 'rating', 'subject', 'content'],
+    components: {
+        Rating
+    }
+}
+</script>
+
diff --git a/erpnext/public/js/hub/pages/Item.vue b/erpnext/public/js/hub/pages/Item.vue
index 4ed3576..4e91832 100644
--- a/erpnext/public/js/hub/pages/Item.vue
+++ b/erpnext/public/js/hub/pages/Item.vue
@@ -28,7 +28,7 @@
 
 		</detail-view>
 
-		<review-area :hub_item_name="hub_item_name"></review-area>
+		<review-area :hub_item_name="hub_item_name" :reviews="reviews"></review-area>
 	</div>
 </template>
 
@@ -52,6 +52,7 @@
 			title: null,
 			image: null,
 			sections: [],
+			reviews: [],
 
 			menu_items: [
 				{
@@ -67,12 +68,12 @@
 				{
 					label: __('Edit Details'),
 					condition: this.is_own_item,
-					action: this.report_item
+					action: this.edit_details
 				},
 				{
 					label: __('Unpublish Item'),
 					condition: this.is_own_item,
-					action: this.report_item
+					action: this.unpublish_item
 				}
 			]
 		};
@@ -160,6 +161,7 @@
 				this.item = item;
 
 				this.build_data();
+				this.make_dialogs();
 			});
 		},
 
@@ -168,6 +170,8 @@
 
 			this.image = this.item.image;
 
+			this.reviews = this.item.reviews || [];
+
 			this.sections = [
 				{
 					title: __('Item Description'),
@@ -182,26 +186,9 @@
 			];
 		},
 
-		report_item() {
-			const d = new frappe.ui.Dialog({
-				title: __('Report Item'),
-				fields: [
-					{
-						label: __('Why do think this Item should be removed?'),
-						fieldtype: 'Text',
-						fieldname: 'message'
-					}
-				],
-				primary_action: ({ message }) => {
-					hub.call('add_reported_item', { hub_item_name: this.item.name, message })
-						.then(() => {
-							d.hide();
-							frappe.show_alert(__('Item Reported'));
-						});
-				}
-			});
-
-			d.show();
+		make_dialogs() {
+			this.make_contact_seller_dialog();
+			this.make_report_item_dialog();
 		},
 
 		add_to_saved_items() {
@@ -219,8 +206,8 @@
 			});
 		},
 
-		contact_seller() {
-			const d = new frappe.ui.Dialog({
+		make_contact_seller_dialog() {
+			this.contact_seller_dialog = new frappe.ui.Dialog({
 				title: __('Send a message'),
 				fields: [
 					{
@@ -251,8 +238,42 @@
 						});
 				}
 			});
+		},
 
-			d.show();
+		make_report_item_dialog() {
+			this.report_item_dialog = new frappe.ui.Dialog({
+				title: __('Report Item'),
+				fields: [
+					{
+						label: __('Why do think this Item should be removed?'),
+						fieldtype: 'Text',
+						fieldname: 'message'
+					}
+				],
+				primary_action: ({ message }) => {
+					hub.call('add_reported_item', { hub_item_name: this.item.name, message })
+						.then(() => {
+							d.hide();
+							frappe.show_alert(__('Item Reported'));
+						});
+				}
+			});
+		},
+
+		contact_seller() {
+			this.contact_seller_dialog.show();
+		},
+
+		report_item() {
+			this.report_item_dialog.show();
+		},
+
+		edit_details() {
+			//
+		},
+
+		unpublish_item() {
+			//
 		}
 	}
 }
diff --git a/erpnext/public/js/hub/pages/subpage.js b/erpnext/public/js/hub/pages/subpage.js
deleted file mode 100644
index 162aa52..0000000
--- a/erpnext/public/js/hub/pages/subpage.js
+++ /dev/null
@@ -1,86 +0,0 @@
-export default class SubPage {
-	constructor(parent, ...options) {
-		this.$parent = $(parent);
-		this.options = options;
-		this.make_wrapper(options);
-
-		// generic action handler
-		this.$wrapper.on('click', '[data-action]', e => {
-			const $target = $(e.currentTarget);
-			const action = $target.data().action;
-
-			if (action && this[action]) {
-				this[action].apply(this, $target);
-			}
-		})
-
-		// handle broken images after every render
-		if (this.render) {
-			this._render = this.render.bind(this);
-
-			this.render = (...args) => {
-				this._render(...args);
-				frappe.dom.handle_broken_images(this.$wrapper);
-			}
-		}
-	}
-
-	make_wrapper() {
-		const page_name = frappe.get_route()[1];
-		this.$wrapper = $(`<div class="marketplace-page"
-			data-page-name="${page_name}">`
-		).appendTo(this.$parent);
-
-		this.hide();
-	}
-
-	add_section({ title, body } = {}) {
-		this._sections = this._sections || {};
-
-		if (title && this._sections[title]) {
-			return this._sections[title];
-		}
-
-		const $section = $(`
-			<div class="row hub-section">
-				<div class="col-sm-12 hub-section-header padding-bottom flex">
-					<h4>${title || ''}</h4>
-				</div>
-				<div class="col-sm-12 hub-section-body">
-					${body || ''}
-				</div>
-			</div>
-		`);
-
-		if (title) {
-			this._sections[title] = $section;
-		}
-
-		this.$wrapper.append($section);
-		return $section;
-	}
-
-	add_back_link(title, route) {
-		const $section = this.add_section();
-		this.$wrapper.prepend($section);
-
-		$section.addClass('margin-bottom');
-		$section.find('.hub-section-header').remove()
-		$section.find('.hub-section-body').html(`
-			<button class="btn btn-xs btn-default" data-route="${route}">${title}</button>
-		`);
-	}
-
-	empty() {
-		this.$wrapper.empty();
-	}
-
-	show() {
-		this.refresh();
-		this.$wrapper.show();
-	}
-
-	hide() {
-		this.$wrapper.hide();
-	}
-}