[hub][vue] DetailView and Profile page
diff --git a/erpnext/public/js/hub/components/DetailView.vue b/erpnext/public/js/hub/components/DetailView.vue
new file mode 100644
index 0000000..ae6e8ab
--- /dev/null
+++ b/erpnext/public/js/hub/components/DetailView.vue
@@ -0,0 +1,54 @@
+<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 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"
+			: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>
+</template>
+
+<script>
+
+export default {
+	name: 'detail-view',
+	props: ['title', 'subtitles', 'image', 'sections'],
+	data() {
+		return {
+			back_to_home_text: __('Back to Home')
+		}
+	},
+	computed: {}
+}
+</script>
+
+<style lang="less" scoped>
+</style>
diff --git a/erpnext/public/js/hub/components/detail_view.js b/erpnext/public/js/hub/components/detail_view.js
index f161e45..fca6a56 100644
--- a/erpnext/public/js/hub/components/detail_view.js
+++ b/erpnext/public/js/hub/components/detail_view.js
@@ -132,42 +132,6 @@
 	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 {
 	get_detail_view_html,
 	get_profile_html
diff --git a/erpnext/public/js/hub/marketplace.js b/erpnext/public/js/hub/marketplace.js
index d8bfea8..433f7da 100644
--- a/erpnext/public/js/hub/marketplace.js
+++ b/erpnext/public/js/hub/marketplace.js
@@ -3,7 +3,6 @@
 // pages
 import './pages/item';
 import './pages/seller';
-import './pages/profile';
 import './pages/messages';
 import './pages/buying_messages';
 import './pages/not_found';
@@ -14,6 +13,7 @@
 import Category from './pages/Category.vue';
 import Search from './pages/Search.vue';
 import PublishedProducts from './pages/PublishedProducts.vue';
+import Profile from './pages/Profile.vue';
 
 // components
 import { ProfileDialog } from './components/profile_dialog';
@@ -203,7 +203,7 @@
 		}
 
 		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) {
@@ -374,3 +374,21 @@
 		$('[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();
+	}
+}
diff --git a/erpnext/public/js/hub/pages/Profile.vue b/erpnext/public/js/hub/pages/Profile.vue
new file mode 100644
index 0000000..2f3c9d5
--- /dev/null
+++ b/erpnext/public/js/hub/pages/Profile.vue
@@ -0,0 +1,66 @@
+<template>
+	<div
+		class="marketplace-page"
+		:data-page-name="page_name"
+	>
+
+		<detail-view v-if="profile"
+			:title="title"
+			:subtitles="subtitles"
+			:image="image"
+			:sections="sections"
+		>
+		</detail-view>
+	</div>
+</template>
+
+<script>
+import DetailView from '../components/DetailView.vue';
+
+export default {
+	name: 'saved-products-page',
+	components: {
+		DetailView
+	},
+	data() {
+		return {
+			page_name: frappe.get_route()[1],
+			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.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>
diff --git a/erpnext/public/js/hub/pages/SavedProducts.vue b/erpnext/public/js/hub/pages/SavedProducts.vue
index 6e5eeff..f113a20 100644
--- a/erpnext/public/js/hub/pages/SavedProducts.vue
+++ b/erpnext/public/js/hub/pages/SavedProducts.vue
@@ -71,7 +71,7 @@
 			}
 
 			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,
 				{
 					'undo-remove': undo_remove.bind(this)
diff --git a/erpnext/public/js/hub/pages/profile.js b/erpnext/public/js/hub/pages/profile.js
deleted file mode 100644
index 9bfa85d..0000000
--- a/erpnext/public/js/hub/pages/profile.js
+++ /dev/null
@@ -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`
-			}
-		}
-	}
-}