From b5a1fdd4c7597ebdd4ab6022e189da9ca3451dbb Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 27 Jul 2020 08:46:21 +0900
Subject: refactor(client): Do not mutate prop directly

Related #6595
---
 src/client/components/note.vue | 91 +++++++++++++++++-------------------------
 1 file changed, 36 insertions(+), 55 deletions(-)

(limited to 'src/client/components/note.vue')

diff --git a/src/client/components/note.vue b/src/client/components/note.vue
index f3e2bb8ba9..dc3cce9e57 100644
--- a/src/client/components/note.vue
+++ b/src/client/components/note.vue
@@ -1,7 +1,7 @@
 <template>
 <div
 	class="note _panel"
-	v-show="!isDeleted && !hideThisNote"
+	v-show="!isDeleted"
 	:tabindex="!isDeleted ? '-1' : null"
 	:class="{ renote: isRenote }"
 	v-hotkey="keymap"
@@ -37,16 +37,16 @@
 		<mk-avatar class="avatar" :user="appearNote.user" v-once/>
 		<div class="main">
 			<x-note-header class="header" :note="appearNote" :mini="true"/>
-			<div class="body" v-if="appearNote.deletedAt == null" ref="noteBody">
+			<div class="body" ref="noteBody">
 				<p v-if="appearNote.cw != null" class="cw">
-				<mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis" v-once/>
+				<mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="emojis" v-once/>
 					<x-cw-button v-model="showContent" :note="appearNote"/>
 				</p>
 				<div class="content" v-show="appearNote.cw == null || showContent">
 					<div class="text">
 						<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
 						<router-link class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><fa :icon="faReply"/></router-link>
-						<mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis" v-once/>
+						<mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="emojis" v-once/>
 						<a class="rp" v-if="appearNote.renote != null">RN:</a>
 					</div>
 					<div class="files" v-if="appearNote.files.length > 0">
@@ -57,8 +57,8 @@
 					<div class="renote" v-if="appearNote.renote"><x-note-preview :note="appearNote.renote"/></div>
 				</div>
 			</div>
-			<footer v-if="appearNote.deletedAt == null" class="footer">
-				<x-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
+			<footer class="footer">
+				<x-reactions-viewer :note="appearNote" :reactions="reactions" :my-reaction="myReaction" :emojis="emojis" ref="reactionsViewer"/>
 				<button @click="reply()" class="button _button">
 					<template v-if="appearNote.reply"><fa :icon="faReplyAll"/></template>
 					<template v-else><fa :icon="faReply"/></template>
@@ -70,17 +70,16 @@
 				<button v-else class="button _button">
 					<fa :icon="faBan"/>
 				</button>
-				<button v-if="!isMyNote && appearNote.myReaction == null" class="button _button" @click="react()" ref="reactButton">
+				<button v-if="!isMyNote && myReaction == null" class="button _button" @click="react()" ref="reactButton">
 					<fa :icon="faPlus"/>
 				</button>
-				<button v-if="!isMyNote && appearNote.myReaction != null" class="button _button reacted" @click="undoReact(appearNote)" ref="reactButton">
+				<button v-if="!isMyNote && myReaction != null" class="button _button reacted" @click="undoReact()" ref="reactButton">
 					<fa :icon="faMinus"/>
 				</button>
 				<button class="button _button" @click="menu()" ref="menuButton">
 					<fa :icon="faEllipsisH"/>
 				</button>
 			</footer>
-			<div class="deleted" v-if="appearNote.deletedAt != null">{{ $t('deleted') }}</div>
 		</div>
 	</article>
 	<x-sub v-for="note in replies" :key="note.id" :note="note" class="reply" :detail="true"/>
@@ -142,7 +141,10 @@ export default Vue.extend({
 			conversation: [],
 			replies: [],
 			showContent: false,
-			hideThisNote: false,
+			isDeleted: false,
+			myReaction: null,
+			reactions: {},
+			emojis: [],
 			noteBody: this.$refs.noteBody,
 			faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug
 		};
@@ -186,10 +188,6 @@ export default Vue.extend({
 			return this.isRenote ? this.note.renote : this.note;
 		},
 
-		isDeleted(): boolean {
-			return this.appearNote.deletedAt != null || this.note.deletedAt != null;
-		},
-
 		isMyNote(): boolean {
 			return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.appearNote.userId);
 		},
@@ -203,9 +201,7 @@ export default Vue.extend({
 		},
 
 		reactionsCount(): number {
-			return this.appearNote.reactions
-				? sum(Object.values(this.appearNote.reactions))
-				: 0;
+			return sum(Object.values(this.reactions));
 		},
 
 		urls(): string[] {
@@ -232,6 +228,10 @@ export default Vue.extend({
 	},
 
 	created() {
+		this.emojis = [...this.appearNote.emojis];
+		this.reactions = { ...this.appearNote.reactions };
+		this.myReaction = this.appearNote.myReaction;
+
 		if (this.$store.getters.isSignedIn) {
 			this.connection = this.$root.stream;
 		}
@@ -261,7 +261,7 @@ export default Vue.extend({
 			this.connection.on('_connected_', this.onStreamConnected);
 		}
 
-		this.noteBody = this.$refs.noteBody
+		this.noteBody = this.$refs.noteBody;
 	},
 
 	beforeDestroy() {
@@ -277,7 +277,7 @@ export default Vue.extend({
 			(this as any).$root.api('promo/read', {
 				noteId: this.appearNote.id
 			});
-			this.hideThisNote = true;
+			this.isDeleted = true;
 		},
 
 		capture(withHandler = false) {
@@ -310,26 +310,20 @@ export default Vue.extend({
 					const reaction = body.reaction;
 
 					if (body.emoji) {
-						const emojis = this.appearNote.emojis || [];
-						if (!emojis.includes(body.emoji)) {
-							emojis.push(body.emoji);
-							Vue.set(this.appearNote, 'emojis', emojis);
+						if (!this.emojis.includes(body.emoji)) {
+							this.emojis.push(body.emoji);
 						}
 					}
 
-					if (this.appearNote.reactions == null) {
-						Vue.set(this.appearNote, 'reactions', {});
-					}
-
-					if (this.appearNote.reactions[reaction] == null) {
-						Vue.set(this.appearNote.reactions, reaction, 0);
+					if (this.reactions[reaction] == null) {
+						Vue.set(this.reactions, reaction, 0);
 					}
 
 					// Increment the count
-					this.appearNote.reactions[reaction]++;
+					this.reactions[reaction]++;
 
-					if (body.userId == this.$store.state.i.id) {
-						Vue.set(this.appearNote, 'myReaction', reaction);
+					if (body.userId === this.$store.state.i.id) {
+						this.myReaction = reaction;
 					}
 					break;
 				}
@@ -337,19 +331,15 @@ export default Vue.extend({
 				case 'unreacted': {
 					const reaction = body.reaction;
 
-					if (this.appearNote.reactions == null) {
-						return;
-					}
-
-					if (this.appearNote.reactions[reaction] == null) {
+					if (this.reactions[reaction] == null) {
 						return;
 					}
 
 					// Decrement the count
-					if (this.appearNote.reactions[reaction] > 0) this.appearNote.reactions[reaction]--;
+					if (this.reactions[reaction] > 0) this.reactions[reaction]--;
 
-					if (body.userId == this.$store.state.i.id) {
-						Vue.set(this.appearNote, 'myReaction', null);
+					if (body.userId === this.$store.state.i.id) {
+						this.myReaction = null;
 					}
 					break;
 				}
@@ -357,19 +347,14 @@ export default Vue.extend({
 				case 'pollVoted': {
 					const choice = body.choice;
 					this.appearNote.poll.choices[choice].votes++;
-					if (body.userId == this.$store.state.i.id) {
+					if (body.userId === this.$store.state.i.id) {
 						Vue.set(this.appearNote.poll.choices[choice], 'isVoted', true);
 					}
 					break;
 				}
 
 				case 'deleted': {
-					Vue.set(this.appearNote, 'deletedAt', body.deletedAt);
-					Vue.set(this.appearNote, 'renote', null);
-					this.appearNote.text = null;
-					this.appearNote.fileIds = [];
-					this.appearNote.poll = null;
-					this.appearNote.cw = null;
+					this.isDeleted = true;
 					break;
 				}
 			}
@@ -442,11 +427,11 @@ export default Vue.extend({
 			});
 		},
 
-		undoReact(note) {
-			const oldReaction = note.myReaction;
+		undoReact() {
+			const oldReaction = this.myReaction;
 			if (!oldReaction) return;
 			this.$root.api('notes/reactions/delete', {
-				noteId: note.id
+				noteId: this.appearNote.id
 			});
 		},
 
@@ -638,7 +623,7 @@ export default Vue.extend({
 						this.$root.api('notes/delete', {
 							noteId: this.note.id
 						});
-						Vue.set(this.note, 'deletedAt', new Date());
+						this.isDeleted = true;
 					}
 				}],
 				source: this.$refs.renoteTime,
@@ -925,10 +910,6 @@ export default Vue.extend({
 					}
 				}
 			}
-
-			> .deleted {
-				opacity: 0.7;
-			}
 		}
 	}
 
-- 
cgit v1.2.3-freya

