Browse Source

Refactor component, add modal of users who liked post

sbkwgh 7 years ago
parent
commit
09401a1e83
1 changed files with 137 additions and 70 deletions
  1. 137 70
      frontend/src/components/HeartButton.vue

+ 137 - 70
frontend/src/components/HeartButton.vue

@@ -1,27 +1,55 @@
 <template>
-	<label class='heart_button' :class='{"heart_button--unlikeable": !likeable}'>
-		<input
-			type='checkbox'
-			:disabled='!likeable'
-			:checked='liked'
-			v-on:change="change"
-		>
-		<span class='fa'></span>
-		<span class='heart_button__count'>{{likes}}</span>
-	</label>
+	<div class='heart_button'>
+		<modal-window v-model='showModal' :close-button='true'>
+			<div class='heart_button__modal'>
+				<div class='heart_button__modal__header'>Likes</div>
+				<div
+					class='heart_button__modal__user'
+					v-for='user in likes'
+					@click='$router.push("/user/" + user.username)'
+				>
+					<avatar-icon
+						:user='user'
+						size='small'
+					></avatar-icon>	
+					<div class='heart_button__modal__username'>{{user.username}}</div>
+				</div>
+
+				<div class='heart_button__modal__empty' v-if='!likes.length'>
+					No likes
+				</div>
+			</div>
+		</modal-window>
+
+		<span
+			class='heart_button__heart fa'
+			:class='{
+				"heart_button__heart--unlikeable": !likeable,
+				"heart_button__heart--liked": liked
+			}'
+			@click='changeLike'
+		></span>
+		<span class='heart_button__count' @click='showModal = true'>{{likes.length}}</span>
+	</div>
 </template>
 
 <script>
+	import ModalWindow from './ModalWindow'
+	import AvatarIcon from './AvatarIcon'
+
 	import AjaxErrorHandler from '../assets/js/errorHandler'
 
 	export default {
 		name: 'HeartButton',
 		props: ['post'],
+		components: {
+			ModalWindow,
+			AvatarIcon
+		},
 		data () {
 			return {
-				changed: false,
-				likes_: undefined,
-				liked_: false
+				likes: this.post.Likes,
+				showModal: false
 			}
 		},
 		computed: {
@@ -35,60 +63,50 @@
 					postUsername !== this.$store.state.username
 				)
 			},
-			likes: {
-				get () {
-					let likes = this.post.Likes.length
-
-					if(this.changed) {
-						return this.likes_
-					} else {
-						return likes
-					}
-				}
-			},
-			liked: {
-				get () {
-					if(this.changed) {
-						return this.liked_
-					} else {
-						return this.post.Likes.some(u => {
-							return u.username === this.$store.state.username
-						})
-					}
-				},
-				set (val) {
-					if(this.likes_ === undefined) {
-						this.likes_ = this.post.Likes.length + (val ? 1 : -1)
-					} else {
-						this.likes_+= val ? 1 : -1
-					}
-
-					this.changed = true
-					this.liked_ = val
-				}
+			liked () {
+				return this.likes.some(u => {
+					return u.username === this.$store.state.username
+				})
 			}
 		},
 		methods: {
-			change (e) {
-				let liked = e.target.checked
+			getIndexOfUser () {
+				let index
+
+				for(let i = 0; i < this.likes.length; i++) {
+					let user = this.likes[i]
+
+					if(user.username === this.$store.state.username) {
+						index = i
+						break
+					}
+				}
+
+				return index
+			},
+			changeLike (e) {
 				let id = this.post.id
-				
-				if(liked) {
+
+				if(!this.likeable) return
+
+				if(!this.liked) {
 					this.axios
 						.put('/api/v1/post/' + id + '/like')
-						.then(_ => this.liked = true)
-						.catch((err) => {
-							e.target.checked = !liked
-							AjaxErrorHandler(this.$store)(err)
+						.then(() => {
+							return this.axios
+								.get('/api/v1/user/' + this.$store.state.username)
+						})
+						.then(res => {
+							this.likes.push(res.data)
 						})
+						.catch(AjaxErrorHandler(this.$store))
 				} else {
 					this.axios
-						.delete('/api/v1/post/' + id + '/like')
-						.then(_ => this.liked = false)
-						.catch((err) => {
-							e.target.checked = !liked
-							AjaxErrorHandler(this.$store)(err)
+						.delete('/api/v1/post/' + id + '/like')	
+						.then(() => {
+							this.likes.splice(this.getIndexOfUser(), 1)
 						})
+						.catch(AjaxErrorHandler(this.$store))
 				}
 			}
 		}
@@ -99,37 +117,86 @@
 	@import '../assets/scss/variables.scss';
 
 	.heart_button {
-		cursor: pointer;
-		@include user-select(none);
+		@at-root #{&}__modal {
+			padding: 1rem;
 
-		@at-root #{&}--unlikeable {
-			cursor: not-allowed;
-		}
+			@at-root #{&}__header {
+				font-size: 1.5rem;
+				font-weight: bold;
+				margin-bottom: 0.25rem;
+			}
+			@at-root #{&}__user {
+				display: flex;
+				align-items: centre;
+				line-height: 2.2rem;
+				max-height: 3rem;
+				padding: 0.25rem;
+				margin: 0 -0.25rem;
+				border-bottom: solid thin $color__gray--primary;
+				transition: background-color 0.2s;
+
+				&:hover {
+					background-color: $color__lightgray--primary;
+				}
 
-		input {
-			display: none;
+				&:last-child {
+					border-bottom: none;
+				}
+			}
+			@at-root #{&}__username {
+				cursor: default;
+				font-size: 1.25rem;
+				margin-left: 0.5rem;
+				margin-bottom: -0.4rem;
+			}
+			@at-root #{&}__empty {
+				text-align: center;
+				font-size: 1.5rem;
+				user-select: none;
+				cursor: default;
+				color: $color__gray--darkest;
+				font-style: italic;
+				margin-bottom: 0.5rem;
+			}
 		}
 
-		#{&}__count {
+		@at-root #{&}__count {
+			@include user-select(none);
+
 			position: relative;
 			bottom: 0.0625rem;
+			cursor: default;
 		}
 
-		span.fa {
+		@at-root #{&}__heart {
+			@include user-select(none);
+
+			cursor: pointer;
 			color: $color__gray--darkest;
-			transition: text-shadow 0.2s, color 0.2s, filter 0.2s;
+			transition: transform 0.2s, text-shadow 0.2s, color 0.2s, filter 0.2s;
 			font-size: 1.125rem;
 
 			&:hover {
 				filter: brightness(0.9);
+				transform: scale(1.1);
 			}
 
 			&::before {
 				content: "\f004";
 			}
-		}
-		input:checked + span.fa {
-			color: #E91E63;
+
+
+			@at-root #{&}--liked {
+				color: #E91E63;
+			}
+			@at-root #{&}--unlikeable {
+				cursor: default;
+
+				&:hover {
+					filter: none;
+					transform: none;
+				}
+			}
 		}
 	}
 </style>