From 8630f91a13e8b8f7b56d2cb3dd2b700ad5ebd6f6 Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Sun, 30 Oct 2016 16:12:35 +0100
Subject: [PATCH] Add favorite-button.

---
 .../favorite_button/favorite_button.js        | 22 ++++++++++++++++++
 .../favorite_button/favorite_button.vue       | 14 +++++++++++
 src/components/status/status.js               |  5 ++--
 src/components/status/status.vue              | 10 ++++----
 src/modules/statuses.js                       | 17 ++++++++++++++
 src/modules/users.js                          |  5 +++-
 src/services/api/api.service.js               | 23 +++++++++++++++----
 7 files changed, 85 insertions(+), 11 deletions(-)
 create mode 100644 src/components/favorite_button/favorite_button.js
 create mode 100644 src/components/favorite_button/favorite_button.vue

diff --git a/src/components/favorite_button/favorite_button.js b/src/components/favorite_button/favorite_button.js
new file mode 100644
index 00000000..0a8843ea
--- /dev/null
+++ b/src/components/favorite_button/favorite_button.js
@@ -0,0 +1,22 @@
+const FavoriteButton = {
+  props: [ 'status' ],
+  methods: {
+    favorite () {
+      if (!this.status.favorited) {
+        this.$store.dispatch('favorite', { id: this.status.id})
+      } else {
+        this.$store.dispatch('unfavorite', { id: this.status.id})
+      }
+    }
+  },
+  computed: {
+    classes () {
+      return {
+        'icon-star-empty': !this.status.favorited,
+        'icon-star': this.status.favorited
+      }
+    }
+  }
+}
+
+export default FavoriteButton
diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue
new file mode 100644
index 00000000..0455c706
--- /dev/null
+++ b/src/components/favorite_button/favorite_button.vue
@@ -0,0 +1,14 @@
+<template>
+  <div>
+    <i :class='classes' class='favorite-button fa' v-on:click.prevent='favorite()'></i>
+    <span v-if='status.fave_num > 0'>{{status.fave_num}}</span>
+  </div>
+</template>
+
+<script src="./favorite_button.js" ></script>
+
+<style>
+ .favorite-button {
+     cursor: pointer
+ }
+</style>
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 6ee8f0dd..f3816daa 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -1,4 +1,5 @@
 import Attachment from '../attachment/attachment.vue'
+import FavoriteButton from '../favorite_button/favorite_button.vue'
 
 const Status = {
   props: [ 'statusoid' ],
@@ -14,9 +15,9 @@ const Status = {
     }
   },
   components: {
-    Attachment
+    Attachment,
+    FavoriteButton
   }
 }
 
 export default Status
-
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index a6a5aac2..4d8700d5 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -23,7 +23,9 @@
           <small>{{status.created_at_parsed}}</small>
         </h4>
 
-        <div v-html="status.statusnet_html"></div>
+        <p>
+          <div v-html="status.statusnet_html"></div>
+        </p>
 
         <div v-if='status.attachments' class='attachments'>
           <attachment :status-id="status.id" :nsfw="status.nsfw" :attachment="attachment" v-for="attachment in status.attachments">
@@ -33,12 +35,12 @@
         <div>
           <div class='status-actions'>
             <div ng-click="toggleReplying()">
-              <i class='fa fa-reply'></i>
+              <i class='fa icon-reply'></i>
             </div>
             <div>
-              <i class='fa fa-retweet'></i>
+              <i class='fa icon-retweet'></i>
             </div>
-            <favorite-button status=status></favorite-button>
+            <favorite-button :status=status></favorite-button>
           </div>
 
           <!-- <post-status-form ng-if="replying" toggle="toggleReplying" reply-to-status="status" reply-to="{{status.id}}"></post-status-form> -->
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index d6bdba65..eee368a3 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -1,5 +1,6 @@
 import { map, slice, last, intersectionBy, sortBy, unionBy, toInteger, groupBy, differenceBy, each, find } from 'lodash'
 import moment from 'moment'
+import apiService from '../services/api/api.service.js'
 
 const defaultState = {
   allStatuses: [],
@@ -104,6 +105,18 @@ const updateTimestampsInStatuses = (statuses) => {
 
 const statuses = {
   state: defaultState,
+  actions: {
+    favorite ({ rootState, commit }, status) {
+      // Optimistic favoriting...
+      commit('setFavorited', { status, value: true })
+      apiService.favorite({ id: status.id, credentials: rootState.users.currentUser.credentials })
+    },
+    unfavorite ({ rootState, commit }, status) {
+      // Optimistic favoriting...
+      commit('setFavorited', { status, value: false })
+      apiService.unfavorite({ id: status.id, credentials: rootState.users.currentUser.credentials })
+    }
+  },
   mutations: {
     addNewStatuses (state, { statuses, showImmediately = false, timeline }) {
       state.timelines[timeline] = addStatusesToTimeline(statuses, showImmediately, state.timelines[timeline])
@@ -118,6 +131,10 @@ const statuses = {
     updateTimestamps (state) {
       updateTimestampsInStatuses(state.allStatuses)
     },
+    setFavorited (state, { status, value }) {
+      const newStatus = find(state.allStatuses, status)
+      newStatus.favorited = value
+    },
     setNsfw (state, { id, nsfw }) {
       // For now, walk through all the statuses because the stuff might be in the replied_to_status
       // TODO: Save the replied_tos as references.
diff --git a/src/modules/users.js b/src/modules/users.js
index 3f6864a2..cf2b16f0 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -25,7 +25,10 @@ const users = {
         .then((response) => {
           if (response.ok) {
             response.json()
-              .then((user) => commit('setCurrentUser', user))
+              .then((user) => {
+                user.credentials = userCredentials
+                commit('setCurrentUser', user)
+              })
               .then(() => timelineFetcher.startFetching({store, credentials: userCredentials}))
           }
           commit('endLogin')
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 9e7da9de..5a46451b 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -3,11 +3,11 @@ const LOGIN_URL = '/api/account/verify_credentials.json'
 const FRIENDS_TIMELINE_URL = '/api/statuses/friends_timeline.json'
 const PUBLIC_TIMELINE_URL = '/api/statuses/public_timeline.json'
 const PUBLIC_AND_EXTERNAL_TIMELINE_URL = '/api/statuses/public_and_external_timeline.json'
+const FAVORITE_URL = '/api/favorites/create'
+const UNFAVORITE_URL = '/api/favorites/destroy'
 // const CONVERSATION_URL = '/api/statusnet/conversation/';
 // const STATUS_UPDATE_URL = '/api/statuses/update.json';
 // const MEDIA_UPLOAD_URL = '/api/statusnet/media/upload';
-// const FAVORITE_URL = '/api/favorites/create';
-// const UNFAVORITE_URL = '/api/favorites/destroy';
 
 // const FORM_CONTENT_TYPE = {'Content-Type': 'application/x-www-form-urlencoded'};
 
@@ -43,9 +43,25 @@ const verifyCredentials = (user) => {
   })
 }
 
+const favorite = ({ id, credentials }) => {
+  return fetch(`${FAVORITE_URL}/${id}.json`, {
+    headers: authHeaders(credentials),
+    method: 'POST'
+  })
+}
+
+const unfavorite = ({ id, credentials }) => {
+  return fetch(`${UNFAVORITE_URL}/${id}.json`, {
+    headers: authHeaders(credentials),
+    method: 'POST'
+  })
+}
+
 const apiService = {
   verifyCredentials,
-  fetchTimeline
+  fetchTimeline,
+  favorite,
+  unfavorite
 }
 
 export default apiService
@@ -104,7 +120,6 @@ export default apiService
 //     });
 //   };
 
-//   const favorite = (id) => $http.post(`${FAVORITE_URL}/${id}.json`, null, {headers: authHeaders});
 //   const unfavorite = (id) => $http.post(`${UNFAVORITE_URL}/${id}.json`, null, {headers: authHeaders});
 
 //   // This was impossible to get to work with $http. You're supposed to set Content-Type