From 71e5892308dbcccae3ce55da0c3ab65aa0484627 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 9 May 2020 15:22:50 +0900
Subject: [PATCH] refactor(client): Use getters to avoid watch vuex

---
 src/client/app.ts                        | 109 -----------------------
 src/client/app.vue                       |  26 +-----
 src/client/pages/preferences/sidebar.vue |   3 +-
 src/client/store.ts                      | 107 ++++++++++++++++++++++
 4 files changed, 112 insertions(+), 133 deletions(-)
 delete mode 100644 src/client/app.ts

diff --git a/src/client/app.ts b/src/client/app.ts
deleted file mode 100644
index 6a03526e3..000000000
--- a/src/client/app.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { faTerminal, faHashtag, faBroadcastTower, faFireAlt, faSearch, faStar, faAt, faListUl, faUserClock, faUsers, faCloud, faGamepad, faFileAlt, faSatellite } from '@fortawesome/free-solid-svg-icons';
-import { faBell, faEnvelope, faComments } from '@fortawesome/free-regular-svg-icons';
-
-export function createMenuDef(actions) {
-	return {
-		notifications: {
-			title: 'notifications',
-			icon: faBell,
-			show: store => store.getters.isSignedIn,
-			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadNotification,
-			to: '/my/notifications',
-		},
-		messaging: {
-			title: 'messaging',
-			icon: faComments,
-			show: store => store.getters.isSignedIn,
-			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadMessagingMessage,
-			to: '/my/messaging',
-		},
-		drive: {
-			title: 'drive',
-			icon: faCloud,
-			show: store => store.getters.isSignedIn,
-			to: '/my/drive',
-		},
-		followRequests: {
-			title: 'followRequests',
-			icon: faUserClock,
-			show: store => store.getters.isSignedIn && store.state.i.isLocked,
-			indicate: store => store.getters.isSignedIn && store.state.i.hasPendingReceivedFollowRequest,
-			to: '/my/follow-requests',
-		},
-		featured: {
-			title: 'featured',
-			icon: faFireAlt,
-			to: '/featured',
-		},
-		explore: {
-			title: 'explore',
-			icon: faHashtag,
-			to: '/explore',
-		},
-		announcements: {
-			title: 'announcements',
-			icon: faBroadcastTower,
-			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadAnnouncement,
-			to: '/announcements',
-		},
-		search: {
-			title: 'search',
-			icon: faSearch,
-			action: () => actions.search(),
-		},
-		lists: {
-			title: 'lists',
-			icon: faListUl,
-			show: store => store.getters.isSignedIn,
-			to: '/my/lists',
-		},
-		groups: {
-			title: 'groups',
-			icon: faUsers,
-			show: store => store.getters.isSignedIn,
-			to: '/my/groups',
-		},
-		antennas: {
-			title: 'antennas',
-			icon: faSatellite,
-			show: store => store.getters.isSignedIn,
-			to: '/my/antennas',
-		},
-		mentions: {
-			title: 'mentions',
-			icon: faAt,
-			show: store => store.getters.isSignedIn,
-			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadMentions,
-			to: '/my/mentions',
-		},
-		messages: {
-			title: 'directNotes',
-			icon: faEnvelope,
-			show: store => store.getters.isSignedIn,
-			indicate: store => store.getters.isSignedIn && store.state.i.hasUnreadSpecifiedNotes,
-			to: '/my/messages',
-		},
-		favorites: {
-			title: 'favorites',
-			icon: faStar,
-			show: store => store.getters.isSignedIn,
-			to: '/my/favorites',
-		},
-		pages: {
-			title: 'pages',
-			icon: faFileAlt,
-			show: store => store.getters.isSignedIn,
-			to: '/my/pages',
-		},
-		games: {
-			title: 'games',
-			icon: faGamepad,
-			to: '/games',
-		},
-		scratchpad: {
-			title: 'scratchpad',
-			icon: faTerminal,
-			to: '/scratchpad',
-		},
-	};
-}
diff --git a/src/client/app.vue b/src/client/app.vue
index 96f1d3ad2..170ba9365 100644
--- a/src/client/app.vue
+++ b/src/client/app.vue
@@ -51,7 +51,7 @@
 				</router-link>
 				<template v-for="item in menu">
 					<div v-if="item === '-'" class="divider"></div>
-					<component v-else-if="menuDef[item].display !== false" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" @click="() => { if (menuDef[item].action) menuDef[item].action() }" :to="menuDef[item].to">
+					<component v-else-if="menuDef[item].show !== false" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" @click="() => { if (menuDef[item].action) menuDef[item].action() }" :to="menuDef[item].to">
 						<fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span>
 						<i v-if="menuDef[item].indicated"><fa :icon="faCircle"/></i>
 					</component>
@@ -139,7 +139,6 @@ import { v4 as uuid } from 'uuid';
 import i18n from './i18n';
 import { host, instanceName } from './config';
 import { search } from './scripts/search';
-import { createMenuDef } from './app';
 
 const DESKTOP_THRESHOLD = 1100;
 
@@ -164,7 +163,7 @@ export default Vue.extend({
 			searchQuery: '',
 			searchWait: false,
 			widgetsEditMode: false,
-			menuDef: createMenuDef({
+			menuDef: this.$store.getters.nav({
 				search: this.search
 			}),
 			isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
@@ -241,23 +240,6 @@ export default Vue.extend({
 					id: 'c', data: {}
 				}]);
 			}
-
-			this.$store.watch(state => state.i, i => {
-				for (const def in this.menuDef) {
-					if (this.menuDef[def].indicate) {
-						Vue.set(this.menuDef[def], 'indicated', this.menuDef[def].indicate(this.$store));
-					}
-					if (this.menuDef[def].show) {
-						Vue.set(this.menuDef[def], 'display', this.menuDef[def].show(this.$store));
-					}
-				}
-			}, { immediate: true, deep: true });
-		} else {
-			for (const def in this.menuDef) {
-				if (this.menuDef[def].show) {
-					Vue.set(this.menuDef[def], 'display', this.menuDef[def].show(this.$store));
-				}
-			}
 		}
 	},
 
@@ -445,13 +427,13 @@ export default Vue.extend({
 		},
 
 		more(ev) {
-			const items = Object.keys(this.menuDef).filter(k => !this.menu.includes(k)).map(k => this.menuDef[k]).filter(def => def.show ? def.show(this.$store) : true).map(def => ({
+			const items = Object.keys(this.menuDef).filter(k => !this.menu.includes(k)).map(k => this.menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
 				type: def.to ? 'link' : 'button',
 				text: this.$t(def.title),
 				icon: def.icon,
 				to: def.to,
 				action: def.action,
-				indicate: def.indicate ? def.indicate(this.$store) : false,
+				indicate: def.indicated,
 			}));
 			this.$root.menu({
 				items: [...items, null, {
diff --git a/src/client/pages/preferences/sidebar.vue b/src/client/pages/preferences/sidebar.vue
index 41fcdbc3c..2dced10e7 100644
--- a/src/client/pages/preferences/sidebar.vue
+++ b/src/client/pages/preferences/sidebar.vue
@@ -21,7 +21,6 @@ import MkButton from '../../components/ui/button.vue';
 import MkTextarea from '../../components/ui/textarea.vue';
 import i18n from '../../i18n';
 import { defaultDeviceUserSettings } from '../../store';
-import { createMenuDef } from '../../app';
 
 export default Vue.extend({
 	i18n,
@@ -33,7 +32,7 @@ export default Vue.extend({
 	
 	data() {
 		return {
-			menuDef: createMenuDef({}),
+			menuDef: this.$store.getters.nav({}),
 			items: '',
 			faListUl, faSave, faRedo
 		}
diff --git a/src/client/store.ts b/src/client/store.ts
index c60661d45..23c800184 100644
--- a/src/client/store.ts
+++ b/src/client/store.ts
@@ -1,6 +1,8 @@
 import Vuex from 'vuex';
 import createPersistedState from 'vuex-persistedstate';
 import * as nestedProperty from 'nested-property';
+import { faTerminal, faHashtag, faBroadcastTower, faFireAlt, faSearch, faStar, faAt, faListUl, faUserClock, faUsers, faCloud, faGamepad, faFileAlt, faSatellite, faDoorClosed } from '@fortawesome/free-solid-svg-icons';
+import { faBell, faEnvelope, faComments } from '@fortawesome/free-regular-svg-icons';
 import { apiUrl } from './config';
 
 export const defaultSettings = {
@@ -81,6 +83,111 @@ export default () => new Vuex.Store({
 
 	getters: {
 		isSignedIn: state => state.i != null,
+
+		nav: (state, getters) => actions => ({
+			notifications: {
+				title: 'notifications',
+				icon: faBell,
+				get show() { return getters.isSignedIn; },
+				get indicated() { return getters.isSignedIn && state.i.hasUnreadNotification; },
+				to: '/my/notifications',
+			},
+			messaging: {
+				title: 'messaging',
+				icon: faComments,
+				get show() { return getters.isSignedIn; },
+				get indicated() { return getters.isSignedIn && state.i.hasUnreadMessagingMessage; },
+				to: '/my/messaging',
+			},
+			drive: {
+				title: 'drive',
+				icon: faCloud,
+				get show() { return getters.isSignedIn; },
+				to: '/my/drive',
+			},
+			followRequests: {
+				title: 'followRequests',
+				icon: faUserClock,
+				get show() { return getters.isSignedIn && state.i.isLocked; },
+				get indicated() { return getters.isSignedIn && state.i.hasPendingReceivedFollowRequest; },
+				to: '/my/follow-requests',
+			},
+			featured: {
+				title: 'featured',
+				icon: faFireAlt,
+				to: '/featured',
+			},
+			explore: {
+				title: 'explore',
+				icon: faHashtag,
+				to: '/explore',
+			},
+			announcements: {
+				title: 'announcements',
+				icon: faBroadcastTower,
+				get indicated() { return getters.isSignedIn && state.i.hasUnreadAnnouncement; },
+				to: '/announcements',
+			},
+			search: {
+				title: 'search',
+				icon: faSearch,
+				action: () => actions.search(),
+			},
+			lists: {
+				title: 'lists',
+				icon: faListUl,
+				get show() { return getters.isSignedIn; },
+				to: '/my/lists',
+			},
+			groups: {
+				title: 'groups',
+				icon: faUsers,
+				get show() { return getters.isSignedIn; },
+				to: '/my/groups',
+			},
+			antennas: {
+				title: 'antennas',
+				icon: faSatellite,
+				get show() { return getters.isSignedIn; },
+				to: '/my/antennas',
+			},
+			mentions: {
+				title: 'mentions',
+				icon: faAt,
+				get show() { return getters.isSignedIn; },
+				get indicated() { return getters.isSignedIn && state.i.hasUnreadMentions; },
+				to: '/my/mentions',
+			},
+			messages: {
+				title: 'directNotes',
+				icon: faEnvelope,
+				get show() { return getters.isSignedIn; },
+				get indicated() { return getters.isSignedIn && state.i.hasUnreadSpecifiedNotes; },
+				to: '/my/messages',
+			},
+			favorites: {
+				title: 'favorites',
+				icon: faStar,
+				get show() { return getters.isSignedIn; },
+				to: '/my/favorites',
+			},
+			pages: {
+				title: 'pages',
+				icon: faFileAlt,
+				get show() { return getters.isSignedIn; },
+				to: '/my/pages',
+			},
+			games: {
+				title: 'games',
+				icon: faGamepad,
+				to: '/games',
+			},
+			scratchpad: {
+				title: 'scratchpad',
+				icon: faTerminal,
+				to: '/scratchpad',
+			},
+		}),
 	},
 
 	mutations: {