Merge branch 'masto-remains' into 'develop'
Interactions 2.0, removing last bits of qvitter api. Only login/register and change background remains after that See merge request pleroma/pleroma-fe!792
This commit is contained in:
		
						commit
						b78ad8998d
					
				
					 15 changed files with 110 additions and 36 deletions
				
			
		| 
						 | 
				
			
			@ -3,7 +3,7 @@ import PublicAndExternalTimeline from 'components/public_and_external_timeline/p
 | 
			
		|||
import FriendsTimeline from 'components/friends_timeline/friends_timeline.vue'
 | 
			
		||||
import TagTimeline from 'components/tag_timeline/tag_timeline.vue'
 | 
			
		||||
import ConversationPage from 'components/conversation-page/conversation-page.vue'
 | 
			
		||||
import Mentions from 'components/mentions/mentions.vue'
 | 
			
		||||
import Interactions from 'components/interactions/interactions.vue'
 | 
			
		||||
import DMs from 'components/dm_timeline/dm_timeline.vue'
 | 
			
		||||
import UserProfile from 'components/user_profile/user_profile.vue'
 | 
			
		||||
import Settings from 'components/settings/settings.vue'
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ export default (store) => {
 | 
			
		|||
    { name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
 | 
			
		||||
    { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
 | 
			
		||||
    { name: 'external-user-profile', path: '/users/:id', component: UserProfile },
 | 
			
		||||
    { name: 'mentions', path: '/users/:username/mentions', component: Mentions },
 | 
			
		||||
    { name: 'interactions', path: '/users/:username/interactions', component: Interactions },
 | 
			
		||||
    { name: 'dms', path: '/users/:username/dms', component: DMs },
 | 
			
		||||
    { name: 'settings', path: '/settings', component: Settings },
 | 
			
		||||
    { name: 'registration', path: '/registration', component: Registration },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										25
									
								
								src/components/interactions/interactions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/components/interactions/interactions.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
import Notifications from '../notifications/notifications.vue'
 | 
			
		||||
 | 
			
		||||
const tabModeDict = {
 | 
			
		||||
  mentions: ['mention'],
 | 
			
		||||
  'likes+repeats': ['repeat', 'like'],
 | 
			
		||||
  follows: ['follow']
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Interactions = {
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      filterMode: tabModeDict['mentions']
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    onModeSwitch (index, dataset) {
 | 
			
		||||
      this.filterMode = tabModeDict[dataset.filter]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  components: {
 | 
			
		||||
    Notifications
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default Interactions
 | 
			
		||||
							
								
								
									
										25
									
								
								src/components/interactions/interactions.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/components/interactions/interactions.vue
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="panel panel-default">
 | 
			
		||||
    <div class="panel-heading">
 | 
			
		||||
      <div class="title">
 | 
			
		||||
        Interactions
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <tab-switcher
 | 
			
		||||
      ref="tabSwitcher"
 | 
			
		||||
      :onSwitch="onModeSwitch"
 | 
			
		||||
      >
 | 
			
		||||
      <span data-tab-dummy data-filter="mentions" :label="$t('nav.mentions')"/>
 | 
			
		||||
      <span data-tab-dummy data-filter="likes+repeats" :label="$t('interactions.favs_repeats')"/>
 | 
			
		||||
      <span data-tab-dummy data-filter="follows" :label="$t('interactions.follows')"/>
 | 
			
		||||
    </tab-switcher>
 | 
			
		||||
    <Notifications
 | 
			
		||||
      ref="notifications"
 | 
			
		||||
      :noHeading="true"
 | 
			
		||||
      :minimalMode="true"
 | 
			
		||||
      :filterMode="filterMode"
 | 
			
		||||
      />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script src="./interactions.js"></script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <Timeline :title="$t('nav.mentions')" v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/>
 | 
			
		||||
  <Timeline :title="$t('nav.interactions')" v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script src="./mentions.js"></script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,8 +8,8 @@
 | 
			
		|||
          </router-link>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li v-if='currentUser'>
 | 
			
		||||
          <router-link :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
 | 
			
		||||
            {{ $t("nav.mentions") }}
 | 
			
		||||
          <router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
 | 
			
		||||
            {{ $t("nav.interactions") }}
 | 
			
		||||
          </router-link>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li v-if='currentUser'>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,15 +7,24 @@ import {
 | 
			
		|||
} from '../../services/notification_utils/notification_utils.js'
 | 
			
		||||
 | 
			
		||||
const Notifications = {
 | 
			
		||||
  props: [
 | 
			
		||||
    'noHeading'
 | 
			
		||||
  ],
 | 
			
		||||
  props: {
 | 
			
		||||
    // Disables display of panel header
 | 
			
		||||
    noHeading: Boolean,
 | 
			
		||||
    // Disables panel styles, unread mark, potentially other notification-related actions
 | 
			
		||||
    // meant for "Interactions" timeline
 | 
			
		||||
    minimalMode: Boolean,
 | 
			
		||||
    // Custom filter mode, an array of strings, possible values 'mention', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline
 | 
			
		||||
    filterMode: Array
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      bottomedOut: false
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    mainClass () {
 | 
			
		||||
      return this.minimalMode ? '' : 'panel panel-default'
 | 
			
		||||
    },
 | 
			
		||||
    notifications () {
 | 
			
		||||
      return notificationsFromStore(this.$store)
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +35,8 @@ const Notifications = {
 | 
			
		|||
      return unseenNotificationsFromStore(this.$store)
 | 
			
		||||
    },
 | 
			
		||||
    visibleNotifications () {
 | 
			
		||||
      return visibleNotificationsFromStore(this.$store)
 | 
			
		||||
      console.log(this.filterMode)
 | 
			
		||||
      return visibleNotificationsFromStore(this.$store, this.filterMode)
 | 
			
		||||
    },
 | 
			
		||||
    unseenCount () {
 | 
			
		||||
      return this.unseenNotifications.length
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,10 @@
 | 
			
		|||
@import '../../_variables.scss';
 | 
			
		||||
 | 
			
		||||
.notifications {
 | 
			
		||||
  &:not(.minimal) {
 | 
			
		||||
    // a bit of a hack to allow scrolling below notifications
 | 
			
		||||
    padding-bottom: 15em;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .loadmore-error {
 | 
			
		||||
    color: $fallback--text;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="notifications">
 | 
			
		||||
    <div class="panel panel-default">
 | 
			
		||||
  <div :class="{ minimal: minimalMode }" class="notifications">
 | 
			
		||||
    <div :class="mainClass">
 | 
			
		||||
      <div v-if="!noHeading" class="panel-heading">
 | 
			
		||||
        <div class="title">
 | 
			
		||||
          {{$t('notifications.notifications')}}
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@
 | 
			
		|||
        <button v-if="unseenCount" @click.prevent="markAsSeen" class="read-button">{{$t('notifications.read')}}</button>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="panel-body">
 | 
			
		||||
        <div v-for="notification in visibleNotifications" :key="notification.id" class="notification" :class='{"unseen": !notification.seen}'>
 | 
			
		||||
        <div v-for="notification in visibleNotifications" :key="notification.id" class="notification" :class='{"unseen": !minimalMode && !notification.seen}'>
 | 
			
		||||
          <div class="notification-overlay"></div>
 | 
			
		||||
          <notification :notification="notification"></notification>
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,9 @@
 | 
			
		|||
          {{$t('notifications.no_more_notifications')}}
 | 
			
		||||
        </div>
 | 
			
		||||
        <a v-else-if="!loading" href="#" v-on:click.prevent="fetchOlderNotifications()">
 | 
			
		||||
          <div class="new-status-notification text-center panel-footer">{{$t('notifications.load_older')}}</div>
 | 
			
		||||
          <div class="new-status-notification text-center panel-footer">
 | 
			
		||||
            {{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older')}}
 | 
			
		||||
          </div>
 | 
			
		||||
        </a>
 | 
			
		||||
        <div v-else class="new-status-notification text-center panel-footer">
 | 
			
		||||
          <i class="icon-spin3 animate-spin"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,11 @@
 | 
			
		|||
            {{ $t("nav.dms") }}
 | 
			
		||||
          </router-link>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li v-if="currentUser" @click="toggleDrawer">
 | 
			
		||||
          <router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
 | 
			
		||||
            {{ $t("nav.interactions") }}
 | 
			
		||||
          </router-link>
 | 
			
		||||
        </li>
 | 
			
		||||
      </ul>
 | 
			
		||||
      <ul>
 | 
			
		||||
        <li v-if="currentUser" @click="toggleDrawer">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,15 +4,18 @@ import './tab_switcher.scss'
 | 
			
		|||
 | 
			
		||||
export default Vue.component('tab-switcher', {
 | 
			
		||||
  name: 'TabSwitcher',
 | 
			
		||||
  props: ['renderOnlyFocused'],
 | 
			
		||||
  props: ['renderOnlyFocused', 'onSwitch'],
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      active: this.$slots.default.findIndex(_ => _.tag)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    activateTab (index) {
 | 
			
		||||
    activateTab (index, dataset) {
 | 
			
		||||
      return () => {
 | 
			
		||||
        if (typeof this.onSwitch === 'function') {
 | 
			
		||||
          this.onSwitch.call(null, index, this.$slots.default[index].elm.dataset)
 | 
			
		||||
        }
 | 
			
		||||
        this.active = index
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +40,11 @@ export default Vue.component('tab-switcher', {
 | 
			
		|||
 | 
			
		||||
            return (
 | 
			
		||||
              <div class={ classesWrapper.join(' ')}>
 | 
			
		||||
                <button disabled={slot.data.attrs.disabled} onClick={this.activateTab(index)} class={ classesTab.join(' ') }>{slot.data.attrs.label}</button>
 | 
			
		||||
                <button
 | 
			
		||||
                  disabled={slot.data.attrs.disabled}
 | 
			
		||||
                  onClick={this.activateTab(index)}
 | 
			
		||||
                  class={classesTab.join(' ')}>
 | 
			
		||||
                {slot.data.attrs.label}</button>
 | 
			
		||||
              </div>
 | 
			
		||||
            )
 | 
			
		||||
          })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,6 +60,7 @@
 | 
			
		|||
    "chat": "Local Chat",
 | 
			
		||||
    "friend_requests": "Follow Requests",
 | 
			
		||||
    "mentions": "Mentions",
 | 
			
		||||
    "interactions": "Interactions",
 | 
			
		||||
    "dms": "Direct Messages",
 | 
			
		||||
    "public_tl": "Public Timeline",
 | 
			
		||||
    "timeline": "Timeline",
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +79,11 @@
 | 
			
		|||
    "repeated_you": "repeated your status",
 | 
			
		||||
    "no_more_notifications": "No more notifications"
 | 
			
		||||
  },
 | 
			
		||||
  "interactions": {
 | 
			
		||||
    "favs_repeats": "Repeats and Favorites",
 | 
			
		||||
    "follows": "New follows",
 | 
			
		||||
    "load_older": "Load older interactions"
 | 
			
		||||
  },
 | 
			
		||||
  "post_status": {
 | 
			
		||||
    "new_status": "Post new status",
 | 
			
		||||
    "account_not_locked_warning": "Your account is not {0}. Anyone can follow you to view your follower-only posts.",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@
 | 
			
		|||
    "back": "Назад",
 | 
			
		||||
    "chat": "Локальный чат",
 | 
			
		||||
    "mentions": "Упоминания",
 | 
			
		||||
    "interactions": "Взаимодействия",
 | 
			
		||||
    "public_tl": "Публичная лента",
 | 
			
		||||
    "timeline": "Лента",
 | 
			
		||||
    "twkn": "Федеративная лента"
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +37,11 @@
 | 
			
		|||
    "read": "Прочесть",
 | 
			
		||||
    "repeated_you": "повторил(а) ваш статус"
 | 
			
		||||
  },
 | 
			
		||||
  "interactions": {
 | 
			
		||||
    "favs_repeats": "Повторы и фавориты",
 | 
			
		||||
    "follows": "Новые подписки",
 | 
			
		||||
    "load_older": "Загрузить старые взаимодействия"
 | 
			
		||||
  },
 | 
			
		||||
  "post_status": {
 | 
			
		||||
    "account_not_locked_warning": "Ваш аккаунт не {0}. Кто угодно может зафоловить вас чтобы прочитать посты только для подписчиков",
 | 
			
		||||
    "account_not_locked_warning_link": "залочен",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,5 @@
 | 
			
		|||
/* eslint-env browser */
 | 
			
		||||
const LOGIN_URL = '/api/account/verify_credentials.json'
 | 
			
		||||
const ALL_FOLLOWING_URL = '/api/qvitter/allfollowing'
 | 
			
		||||
const MENTIONS_URL = '/api/statuses/mentions.json'
 | 
			
		||||
const REGISTRATION_URL = '/api/account/register.json'
 | 
			
		||||
const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
 | 
			
		||||
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
 | 
			
		||||
| 
						 | 
				
			
			@ -320,13 +318,6 @@ const fetchFollowers = ({id, maxId, sinceId, limit = 20, credentials}) => {
 | 
			
		|||
    .then((data) => data.map(parseUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const fetchAllFollowing = ({username, credentials}) => {
 | 
			
		||||
  const url = `${ALL_FOLLOWING_URL}/${username}.json`
 | 
			
		||||
  return fetch(url, { headers: authHeaders(credentials) })
 | 
			
		||||
    .then((data) => data.json())
 | 
			
		||||
    .then((data) => data.map(parseUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const fetchFollowRequests = ({credentials}) => {
 | 
			
		||||
  const url = FOLLOW_REQUESTS_URL
 | 
			
		||||
  return fetch(url, { headers: authHeaders(credentials) })
 | 
			
		||||
| 
						 | 
				
			
			@ -446,7 +437,6 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
 | 
			
		|||
  const timelineUrls = {
 | 
			
		||||
    public: MASTODON_PUBLIC_TIMELINE,
 | 
			
		||||
    friends: MASTODON_USER_HOME_TIMELINE_URL,
 | 
			
		||||
    mentions: MENTIONS_URL,
 | 
			
		||||
    dms: MASTODON_DIRECT_MESSAGES_TIMELINE_URL,
 | 
			
		||||
    notifications: MASTODON_USER_NOTIFICATIONS_URL,
 | 
			
		||||
    'publicAndExternal': MASTODON_PUBLIC_TIMELINE,
 | 
			
		||||
| 
						 | 
				
			
			@ -747,7 +737,6 @@ const apiService = {
 | 
			
		|||
  postStatus,
 | 
			
		||||
  deleteStatus,
 | 
			
		||||
  uploadMedia,
 | 
			
		||||
  fetchAllFollowing,
 | 
			
		||||
  fetchMutes,
 | 
			
		||||
  muteUser,
 | 
			
		||||
  unmuteUser,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,10 +23,6 @@ const backendInteractorService = (credentials) => {
 | 
			
		|||
    return apiService.fetchFollowers({id, maxId, sinceId, limit, credentials})
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const fetchAllFollowing = ({username}) => {
 | 
			
		||||
    return apiService.fetchAllFollowing({username, credentials})
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const fetchUser = ({id}) => {
 | 
			
		||||
    return apiService.fetchUser({id, credentials})
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +133,6 @@ const backendInteractorService = (credentials) => {
 | 
			
		|||
    unblockUser,
 | 
			
		||||
    fetchUser,
 | 
			
		||||
    fetchUserRelationship,
 | 
			
		||||
    fetchAllFollowing,
 | 
			
		||||
    verifyCredentials: apiService.verifyCredentials,
 | 
			
		||||
    startFetchingTimeline,
 | 
			
		||||
    startFetchingNotifications,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,11 +25,13 @@ const sortById = (a, b) => {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const visibleNotificationsFromStore = store => {
 | 
			
		||||
export const visibleNotificationsFromStore = (store, types) => {
 | 
			
		||||
  // map is just to clone the array since sort mutates it and it causes some issues
 | 
			
		||||
  let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById)
 | 
			
		||||
  sortedNotifications = sortBy(sortedNotifications, 'seen')
 | 
			
		||||
  return sortedNotifications.filter((notification) => visibleTypes(store).includes(notification.type))
 | 
			
		||||
  return sortedNotifications.filter(
 | 
			
		||||
    (notification) => (types || visibleTypes(store)).includes(notification.type)
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const unseenNotificationsFromStore = store =>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue