feat: Buying and BuyingMessages in vue
diff --git a/erpnext/public/js/hub/components/CommentInput.vue b/erpnext/public/js/hub/components/CommentInput.vue
new file mode 100644
index 0000000..cc430d0
--- /dev/null
+++ b/erpnext/public/js/hub/components/CommentInput.vue
@@ -0,0 +1,38 @@
+<template>
+	<div>
+		<div ref="comment-input"></div>
+		<div class="level">
+			<div class="level-left">
+				<span class="text-muted">{{ __('Ctrl + Enter to submit') }}</span>
+			</div>
+			<div class="level-right">
+				<button class="btn btn-primary btn-xs" @click="submit_input">{{ __('Submit') }}</button>
+			</div>
+		</div>
+	</div>
+</template>
+<script>
+export default {
+	mounted() {
+		this.make_input();
+	},
+	methods: {
+		make_input() {
+			this.message_input = new frappe.ui.CommentArea({
+				parent: this.$refs['comment-input'],
+				on_submit: (message) => {
+					this.message_input.reset();
+					this.$emit('change', message);
+				},
+				no_wrapper: true
+			});
+		},
+		submit_input() {
+			if (!this.message_input) return;
+			const value = this.message_input.val();
+			if (!value) return;
+			this.message_input.submit();
+		}
+	}
+}
+</script>
diff --git a/erpnext/public/js/hub/components/ItemListCard.vue b/erpnext/public/js/hub/components/ItemListCard.vue
new file mode 100644
index 0000000..4c68100
--- /dev/null
+++ b/erpnext/public/js/hub/components/ItemListCard.vue
@@ -0,0 +1,23 @@
+<template>
+	<div class="hub-list-item" :data-route="item.route">
+		<div class="hub-list-left">
+			<img class="hub-list-image" v-img-src="item.image">
+			<div class="hub-list-body ellipsis">
+				<div class="hub-list-title">{{item.item_name}}</div>
+				<div class="hub-list-subtitle ellipsis">
+					<span>{{message.sender}}: </span>
+					<span>{{message.content}}</span>
+
+				</div>
+			</div>
+		</div>
+		<div class="hub-list-right">
+			<span class="text-muted" v-html="frappe.datetime.comment_when(message.creation, true)" />
+		</div>
+	</div>
+</template>
+<script>
+export default {
+	props: ['item', 'message']
+}
+</script>
diff --git a/erpnext/public/js/hub/pages/Buying.vue b/erpnext/public/js/hub/pages/Buying.vue
new file mode 100644
index 0000000..7a783bc
--- /dev/null
+++ b/erpnext/public/js/hub/pages/Buying.vue
@@ -0,0 +1,46 @@
+<template>
+	<div>
+		<section-header>
+			<h4>{{ __('Buying') }}</h4>
+		</section-header>
+		<div class="row">
+			<div class="col-md-7"
+				v-for="item of items"
+				:key="item.name"
+			>
+				<item-list-card
+					:item="item"
+					:message="item.recent_message"
+					v-route="'marketplace/buying/' + item.name"
+				/>
+			</div>
+		</div>
+	</div>
+</template>
+<script>
+import SectionHeader from '../components/SectionHeader.vue';
+import ItemListCard from '../components/ItemListCard.vue';
+
+export default {
+	components: {
+		SectionHeader,
+		ItemListCard
+	},
+	data() {
+		return {
+			items: []
+		}
+	},
+	created() {
+		this.get_items_for_messages()
+			.then(items => {
+				this.items = items;
+			});
+	},
+	methods: {
+		get_items_for_messages() {
+			return hub.call('get_buying_items_for_messages', {}, 'action:send_message');
+		}
+	}
+}
+</script>
diff --git a/erpnext/public/js/hub/pages/BuyingMessages.vue b/erpnext/public/js/hub/pages/BuyingMessages.vue
new file mode 100644
index 0000000..c718647
--- /dev/null
+++ b/erpnext/public/js/hub/pages/BuyingMessages.vue
@@ -0,0 +1,88 @@
+<template>
+	<div v-if="item_details">
+
+		<section-header>
+			<div class="flex flex-column margin-bottom">
+				<h4>{{ item_details.item_name }}</h4>
+				<span class="text-muted">{{ item_details.company }}</span>
+			</div>
+		</section-header>
+		<div class="row">
+			<div class="col-md-7">
+				<div class="message-container">
+					<div class="message-list">
+						<div class="level margin-bottom" v-for="message in messages" :key="message.name">
+							<div class="level-left ellipsis" style="width: 80%;">
+								<div v-html="frappe.avatar(message.sender)" />
+								<div style="white-space: normal;" v-html="message.content" />
+							</div>
+							<div class="level-right text-muted" v-html="frappe.datetime.comment_when(message.creation, true)" />
+						</div>
+					</div>
+					<div class="message-input">
+						<comment-input @change="send_message" />
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+<script>
+import SectionHeader from '../components/SectionHeader.vue';
+import CommentInput from '../components/CommentInput.vue';
+import ItemListCard from '../components/ItemListCard.vue';
+
+export default {
+	components: {
+		SectionHeader,
+		CommentInput,
+		ItemListCard
+	},
+	data() {
+		return {
+			item_details: null,
+			messages: []
+		}
+	},
+	created() {
+		const hub_item_code = this.get_hub_item_code();
+		this.get_item_details(hub_item_code)
+			.then(item_details => {
+				this.item_details = item_details;
+				this.get_messages(item_details)
+					.then(messages => {
+						this.messages = messages;
+					});
+			});
+	},
+	methods: {
+		send_message(message) {
+			this.messages.push({
+				sender: hub.settings.company_email,
+				content: message,
+				creation: Date.now(),
+				name: frappe.utils.get_random(6)
+			});
+			hub.call('send_message', {
+				from_seller: hub.settings.company_email,
+				to_seller: this.item_details.hub_seller,
+				hub_item: this.item_details.hub_item_code,
+				message
+			});
+		},
+		get_item_details(hub_item_code) {
+			return hub.call('get_item_details', { hub_item_code })
+		},
+		get_messages() {
+			if (!this.item_details) return [];
+			return hub.call('get_messages', {
+				against_seller: this.item_details.hub_seller,
+				against_item: this.item_details.hub_item_code
+			});
+		},
+		get_hub_item_code() {
+			return frappe.get_route()[2];
+		}
+	}
+}
+</script>
diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less
index 779d45d..4cbe351 100644
--- a/erpnext/public/less/hub.less
+++ b/erpnext/public/less/hub.less
@@ -331,11 +331,10 @@
 		border-radius: 3px;
 		height: calc(100vh - 300px);
 		justify-content: space-between;
+		padding: 15px;
 	}
 
 	.message-list {
-		padding-top: 15px;
-		padding-bottom: 15px;
 		overflow: scroll;
 	}
 }