Merge branch '227-manage-blocks-mutes' into 'develop'
Add Blocks / Mutes management tabs under user settings page See merge request pleroma/pleroma-fe!578
This commit is contained in:
commit
e34e1ccdae
20 changed files with 612 additions and 78 deletions
28
src/components/basic_user_card/basic_user_card.js
Normal file
28
src/components/basic_user_card/basic_user_card.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
||||
const BasicUserCard = {
|
||||
props: [
|
||||
'user'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
userExpanded: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
UserCardContent,
|
||||
UserAvatar
|
||||
},
|
||||
methods: {
|
||||
toggleUserExpanded () {
|
||||
this.userExpanded = !this.userExpanded
|
||||
},
|
||||
userProfileLink (user) {
|
||||
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BasicUserCard
|
92
src/components/basic_user_card/basic_user_card.vue
Normal file
92
src/components/basic_user_card/basic_user_card.vue
Normal file
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<div class="user-card">
|
||||
<router-link :to="userProfileLink(user)">
|
||||
<UserAvatar class="avatar" :compact="true" @click.prevent.native="toggleUserExpanded" :src="user.profile_image_url"/>
|
||||
</router-link>
|
||||
<div class="user-card-expanded-content" v-if="userExpanded">
|
||||
<user-card-content :user="user" :switcher="false"></user-card-content>
|
||||
</div>
|
||||
<div class="user-card-collapsed-content" v-else>
|
||||
<div class="user-card-primary-area">
|
||||
<div :title="user.name" class="user-name">
|
||||
<span v-if="user.name_html" v-html="user.name_html"></span>
|
||||
<span v-else>{{ user.name }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<router-link class='user-screen-name' :to="userProfileLink(user)">
|
||||
@{{user.screen_name}}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-card-secondary-area">
|
||||
<slot name="secondary-area"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./basic_user_card.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.user-card {
|
||||
display: flex;
|
||||
flex: 1 0;
|
||||
padding-top: 0.6em;
|
||||
padding-right: 1em;
|
||||
padding-bottom: 0.6em;
|
||||
padding-left: 1em;
|
||||
border-bottom: 1px solid;
|
||||
margin: 0;
|
||||
border-bottom-color: $fallback--border;
|
||||
border-bottom-color: var(--border, $fallback--border);
|
||||
|
||||
&-collapsed-content {
|
||||
margin-left: 0.7em;
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-primary-area {
|
||||
flex: 1;
|
||||
.user-name {
|
||||
img {
|
||||
object-fit: contain;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-secondary-area {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
&-expanded-content {
|
||||
flex: 1;
|
||||
margin: 0.2em 0 0 0.7em;
|
||||
border-radius: $fallback--panelRadius;
|
||||
border-radius: var(--panelRadius, $fallback--panelRadius);
|
||||
border-style: solid;
|
||||
border-color: $fallback--border;
|
||||
border-color: var(--border, $fallback--border);
|
||||
border-width: 1px;
|
||||
overflow: hidden;
|
||||
|
||||
.panel-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
37
src/components/block_card/block_card.js
Normal file
37
src/components/block_card/block_card.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
||||
|
||||
const BlockCard = {
|
||||
props: ['userId'],
|
||||
data () {
|
||||
return {
|
||||
progress: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
user () {
|
||||
return this.$store.getters.userById(this.userId)
|
||||
},
|
||||
blocked () {
|
||||
return this.user.statusnet_blocking
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BasicUserCard
|
||||
},
|
||||
methods: {
|
||||
unblockUser () {
|
||||
this.progress = true
|
||||
this.$store.dispatch('unblockUser', this.user.id).then(() => {
|
||||
this.progress = false
|
||||
})
|
||||
},
|
||||
blockUser () {
|
||||
this.progress = true
|
||||
this.$store.dispatch('blockUser', this.user.id).then(() => {
|
||||
this.progress = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BlockCard
|
24
src/components/block_card/block_card.vue
Normal file
24
src/components/block_card/block_card.vue
Normal file
|
@ -0,0 +1,24 @@
|
|||
<template>
|
||||
<basic-user-card :user="user">
|
||||
<template slot="secondary-area">
|
||||
<button class="btn btn-default" @click="unblockUser" :disabled="progress" v-if="blocked">
|
||||
<template v-if="progress">
|
||||
{{ $t('user_card.unblock_progress') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('user_card.unblock') }}
|
||||
</template>
|
||||
</button>
|
||||
<button class="btn btn-default" @click="blockUser" :disabled="progress" v-else>
|
||||
<template v-if="progress">
|
||||
{{ $t('user_card.block_progress') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('user_card.block') }}
|
||||
</template>
|
||||
</button>
|
||||
</template>
|
||||
</basic-user-card>
|
||||
</template>
|
||||
|
||||
<script src="./block_card.js"></script>
|
37
src/components/mute_card/mute_card.js
Normal file
37
src/components/mute_card/mute_card.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
||||
|
||||
const MuteCard = {
|
||||
props: ['userId'],
|
||||
data () {
|
||||
return {
|
||||
progress: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
user () {
|
||||
return this.$store.getters.userById(this.userId)
|
||||
},
|
||||
muted () {
|
||||
return this.user.muted
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BasicUserCard
|
||||
},
|
||||
methods: {
|
||||
unmuteUser () {
|
||||
this.progress = true
|
||||
this.$store.dispatch('unmuteUser', this.user.id).then(() => {
|
||||
this.progress = false
|
||||
})
|
||||
},
|
||||
muteUser () {
|
||||
this.progress = true
|
||||
this.$store.dispatch('muteUser', this.user.id).then(() => {
|
||||
this.progress = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MuteCard
|
24
src/components/mute_card/mute_card.vue
Normal file
24
src/components/mute_card/mute_card.vue
Normal file
|
@ -0,0 +1,24 @@
|
|||
<template>
|
||||
<basic-user-card :user="user">
|
||||
<template slot="secondary-area">
|
||||
<button class="btn btn-default" @click="unmuteUser" :disabled="progress" v-if="muted">
|
||||
<template v-if="progress">
|
||||
{{ $t('user_card.unmute_progress') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('user_card.unmute') }}
|
||||
</template>
|
||||
</button>
|
||||
<button class="btn btn-default" @click="muteUser" :disabled="progress" v-else>
|
||||
<template v-if="progress">
|
||||
{{ $t('user_card.mute_progress') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('user_card.mute') }}
|
||||
</template>
|
||||
</button>
|
||||
</template>
|
||||
</basic-user-card>
|
||||
</template>
|
||||
|
||||
<script src="./mute_card.js"></script>
|
|
@ -1,9 +1,33 @@
|
|||
import { unescape } from 'lodash'
|
||||
import { compose } from 'vue-compose'
|
||||
import unescape from 'lodash/unescape'
|
||||
import get from 'lodash/get'
|
||||
|
||||
import TabSwitcher from '../tab_switcher/tab_switcher.js'
|
||||
import ImageCropper from '../image_cropper/image_cropper.vue'
|
||||
import StyleSwitcher from '../style_switcher/style_switcher.vue'
|
||||
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
|
||||
import BlockCard from '../block_card/block_card.vue'
|
||||
import MuteCard from '../mute_card/mute_card.vue'
|
||||
import withSubscription from '../../hocs/with_subscription/with_subscription'
|
||||
import withList from '../../hocs/with_list/with_list'
|
||||
|
||||
const BlockList = compose(
|
||||
withSubscription({
|
||||
fetch: (props, $store) => $store.dispatch('fetchBlocks'),
|
||||
select: (props, $store) => get($store.state.users.currentUser, 'blockIds', []),
|
||||
childPropName: 'entries'
|
||||
}),
|
||||
withList({ getEntryProps: userId => ({ userId }) })
|
||||
)(BlockCard)
|
||||
|
||||
const MuteList = compose(
|
||||
withSubscription({
|
||||
fetch: (props, $store) => $store.dispatch('fetchMutes'),
|
||||
select: (props, $store) => get($store.state.users.currentUser, 'muteIds', []),
|
||||
childPropName: 'entries'
|
||||
}),
|
||||
withList({ getEntryProps: userId => ({ userId }) })
|
||||
)(MuteCard)
|
||||
|
||||
const UserSettings = {
|
||||
data () {
|
||||
|
@ -41,7 +65,9 @@ const UserSettings = {
|
|||
components: {
|
||||
StyleSwitcher,
|
||||
TabSwitcher,
|
||||
ImageCropper
|
||||
ImageCropper,
|
||||
BlockList,
|
||||
MuteList
|
||||
},
|
||||
computed: {
|
||||
user () {
|
||||
|
|
|
@ -162,6 +162,12 @@
|
|||
<h2>{{$t('settings.follow_export_processing')}}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :label="$t('settings.blocks_tab')">
|
||||
<block-list :refresh="true">
|
||||
<template slot="empty">{{$t('settings.no_blocks')}}</template>
|
||||
</block-list>
|
||||
</div>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
</div>
|
||||
|
|
40
src/hocs/with_list/with_list.js
Normal file
40
src/hocs/with_list/with_list.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
import Vue from 'vue'
|
||||
import map from 'lodash/map'
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
import './with_list.scss'
|
||||
|
||||
const defaultEntryPropsGetter = entry => ({ entry })
|
||||
const defaultKeyGetter = entry => entry.id
|
||||
|
||||
const withList = ({
|
||||
getEntryProps = defaultEntryPropsGetter, // function to accept entry and index values and return props to be passed into the item component
|
||||
getKey = defaultKeyGetter // funciton to accept entry and index values and return key prop value
|
||||
}) => (ItemComponent) => (
|
||||
Vue.component('withList', {
|
||||
props: [
|
||||
'entries', // array of entry
|
||||
'entryProps', // additional props to be passed into each entry
|
||||
'entryListeners' // additional event listeners to be passed into each entry
|
||||
],
|
||||
render (createElement) {
|
||||
return (
|
||||
<div class="with-list">
|
||||
{map(this.entries, (entry, index) => {
|
||||
const props = {
|
||||
key: getKey(entry, index),
|
||||
props: {
|
||||
...this.$props.entryProps,
|
||||
...getEntryProps(entry, index)
|
||||
},
|
||||
on: this.$props.entryListeners
|
||||
}
|
||||
return <ItemComponent {...props} />
|
||||
})}
|
||||
{isEmpty(this.entries) && this.$slots.empty && <div class="with-list-empty-content faint">{this.$slots.empty}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
export default withList
|
6
src/hocs/with_list/with_list.scss
Normal file
6
src/hocs/with_list/with_list.scss
Normal file
|
@ -0,0 +1,6 @@
|
|||
.with-list {
|
||||
&-empty-content {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
91
src/hocs/with_load_more/with_load_more.js
Normal file
91
src/hocs/with_load_more/with_load_more.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
import Vue from 'vue'
|
||||
import filter from 'lodash/filter'
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
import './with_load_more.scss'
|
||||
|
||||
const withLoadMore = ({
|
||||
fetch, // function to fetch entries and return a promise
|
||||
select, // function to select data from store
|
||||
childPropName = 'entries' // name of the prop to be passed into the wrapped component
|
||||
}) => (WrappedComponent) => {
|
||||
const originalProps = WrappedComponent.props || []
|
||||
const props = filter(originalProps, v => v !== 'entries')
|
||||
|
||||
return Vue.component('withLoadMore', {
|
||||
render (createElement) {
|
||||
const props = {
|
||||
props: {
|
||||
...this.$props,
|
||||
[childPropName]: this.entries
|
||||
},
|
||||
on: this.$listeners,
|
||||
scopedSlots: this.$scopedSlots
|
||||
}
|
||||
const children = Object.entries(this.$slots).map(([key, value]) => createElement('template', { slot: key }, value))
|
||||
return (
|
||||
<div class="with-load-more">
|
||||
<WrappedComponent {...props}>
|
||||
{children}
|
||||
</WrappedComponent>
|
||||
<div class="with-load-more-footer">
|
||||
{this.error && <a onClick={this.fetchEntries} class="alert error">{this.$t('general.generic_error')}</a>}
|
||||
{!this.error && this.loading && <i class="icon-spin3 animate-spin"/>}
|
||||
{!this.error && !this.loading && !this.bottomedOut && <a onClick={this.fetchEntries}>{this.$t('general.more')}</a>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
props,
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
bottomedOut: false,
|
||||
error: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
entries () {
|
||||
return select(this.$props, this.$store) || []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('scroll', this.scrollLoad)
|
||||
if (this.entries.length === 0) {
|
||||
this.fetchEntries()
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('scroll', this.scrollLoad)
|
||||
},
|
||||
methods: {
|
||||
fetchEntries () {
|
||||
if (!this.loading) {
|
||||
this.loading = true
|
||||
this.error = false
|
||||
fetch(this.$props, this.$store)
|
||||
.then((newEntries) => {
|
||||
this.loading = false
|
||||
this.bottomedOut = isEmpty(newEntries)
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
this.error = true
|
||||
})
|
||||
}
|
||||
},
|
||||
scrollLoad (e) {
|
||||
const bodyBRect = document.body.getBoundingClientRect()
|
||||
const height = Math.max(bodyBRect.height, -(bodyBRect.y))
|
||||
if (this.loading === false &&
|
||||
this.bottomedOut === false &&
|
||||
this.$el.offsetHeight > 0 &&
|
||||
(window.innerHeight + window.pageYOffset) >= (height - 750)
|
||||
) {
|
||||
this.fetchEntries()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default withLoadMore
|
10
src/hocs/with_load_more/with_load_more.scss
Normal file
10
src/hocs/with_load_more/with_load_more.scss
Normal file
|
@ -0,0 +1,10 @@
|
|||
.with-load-more {
|
||||
&-footer {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
|
||||
.error {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
84
src/hocs/with_subscription/with_subscription.js
Normal file
84
src/hocs/with_subscription/with_subscription.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
import Vue from 'vue'
|
||||
import reject from 'lodash/reject'
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
import omit from 'lodash/omit'
|
||||
import './with_subscription.scss'
|
||||
|
||||
const withSubscription = ({
|
||||
fetch, // function to fetch entries and return a promise
|
||||
select, // function to select data from store
|
||||
childPropName = 'content' // name of the prop to be passed into the wrapped component
|
||||
}) => (WrappedComponent) => {
|
||||
const originalProps = WrappedComponent.props || []
|
||||
const props = reject(originalProps, v => v === 'content')
|
||||
|
||||
return Vue.component('withSubscription', {
|
||||
props: [
|
||||
...props,
|
||||
'refresh' // boolean saying to force-fetch data whenever created
|
||||
],
|
||||
render (createElement) {
|
||||
if (!this.error && !this.loading) {
|
||||
const props = {
|
||||
props: {
|
||||
...omit(this.$props, 'refresh'),
|
||||
[childPropName]: this.fetchedData
|
||||
},
|
||||
on: this.$listeners,
|
||||
scopedSlots: this.$scopedSlots
|
||||
}
|
||||
const children = Object.entries(this.$slots).map(([key, value]) => createElement('template', { slot: key }, value))
|
||||
return (
|
||||
<div class="with-subscription">
|
||||
<WrappedComponent {...props}>
|
||||
{children}
|
||||
</WrappedComponent>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div class="with-subscription-loading">
|
||||
{this.error
|
||||
? <a onClick={this.fetchData} class="alert error">{this.$t('general.generic_error')}</a>
|
||||
: <i class="icon-spin3 animate-spin"/>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
error: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fetchedData () {
|
||||
return select(this.$props, this.$store)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.refresh || isEmpty(this.fetchedData)) {
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchData () {
|
||||
if (!this.loading) {
|
||||
this.loading = true
|
||||
this.error = false
|
||||
fetch(this.$props, this.$store)
|
||||
.then(() => {
|
||||
this.loading = false
|
||||
})
|
||||
.catch(() => {
|
||||
this.error = true
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default withSubscription
|
10
src/hocs/with_subscription/with_subscription.scss
Normal file
10
src/hocs/with_subscription/with_subscription.scss
Normal file
|
@ -0,0 +1,10 @@
|
|||
.with-subscription {
|
||||
&-loading {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
|
||||
.error {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -110,6 +110,7 @@
|
|||
"avatarRadius": "Avatars",
|
||||
"background": "Background",
|
||||
"bio": "Bio",
|
||||
"blocks_tab": "Blocks",
|
||||
"btnRadius": "Buttons",
|
||||
"cBlue": "Blue (Reply, follow)",
|
||||
"cGreen": "Green (Retweet)",
|
||||
|
@ -164,6 +165,7 @@
|
|||
"lock_account_description": "Restrict your account to approved followers only",
|
||||
"loop_video": "Loop videos",
|
||||
"loop_video_silent_only": "Loop only videos without sound (i.e. Mastodon's \"gifs\")",
|
||||
"mutes_tab": "Mutes",
|
||||
"play_videos_in_modal": "Play videos directly in the media viewer",
|
||||
"use_contain_fit": "Don't crop the attachment in thumbnails",
|
||||
"name": "Name",
|
||||
|
@ -175,6 +177,8 @@
|
|||
"notification_visibility_mentions": "Mentions",
|
||||
"notification_visibility_repeats": "Repeats",
|
||||
"no_rich_text_description": "Strip rich text formatting from all posts",
|
||||
"no_blocks": "No blocks",
|
||||
"no_mutes": "No mutes",
|
||||
"hide_follows_description": "Don't show who I'm following",
|
||||
"hide_followers_description": "Don't show who's following me",
|
||||
"show_admin_badge": "Show Admin badge in my profile",
|
||||
|
@ -366,7 +370,13 @@
|
|||
"muted": "Muted",
|
||||
"per_day": "per day",
|
||||
"remote_follow": "Remote follow",
|
||||
"statuses": "Statuses"
|
||||
"statuses": "Statuses",
|
||||
"unblock": "Unblock",
|
||||
"unblock_progress": "Unblocking...",
|
||||
"block_progress": "Blocking...",
|
||||
"unmute": "Unmute",
|
||||
"unmute_progress": "Unmuting...",
|
||||
"mute_progress": "Muting..."
|
||||
},
|
||||
"user_profile": {
|
||||
"timeline_title": "User Timeline"
|
||||
|
|
|
@ -85,6 +85,12 @@ export const mutations = {
|
|||
addNewUsers (state, users) {
|
||||
each(users, (user) => mergeOrAdd(state.users, state.usersObject, user))
|
||||
},
|
||||
saveBlocks (state, blockIds) {
|
||||
state.currentUser.blockIds = blockIds
|
||||
},
|
||||
saveMutes (state, muteIds) {
|
||||
state.currentUser.muteIds = muteIds
|
||||
},
|
||||
setUserForStatus (state, status) {
|
||||
status.user = state.usersObject[status.user.id]
|
||||
},
|
||||
|
@ -137,6 +143,38 @@ const users = {
|
|||
store.rootState.api.backendInteractor.fetchUser({ id })
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
},
|
||||
fetchBlocks (store) {
|
||||
return store.rootState.api.backendInteractor.fetchBlocks()
|
||||
.then((blocks) => {
|
||||
store.commit('saveBlocks', map(blocks, 'id'))
|
||||
store.commit('addNewUsers', blocks)
|
||||
return blocks
|
||||
})
|
||||
},
|
||||
blockUser (store, id) {
|
||||
return store.rootState.api.backendInteractor.blockUser(id)
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
},
|
||||
unblockUser (store, id) {
|
||||
return store.rootState.api.backendInteractor.unblockUser(id)
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
},
|
||||
fetchMutes (store) {
|
||||
return store.rootState.api.backendInteractor.fetchMutes()
|
||||
.then((mutedUsers) => {
|
||||
each(mutedUsers, (user) => { user.muted = true })
|
||||
store.commit('addNewUsers', mutedUsers)
|
||||
store.commit('saveMutes', map(mutedUsers, 'id'))
|
||||
})
|
||||
},
|
||||
muteUser (store, id) {
|
||||
return store.state.api.backendInteractor.setUserMute({ id, muted: true })
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
},
|
||||
unmuteUser (store, id) {
|
||||
return store.state.api.backendInteractor.setUserMute({ id, muted: false })
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
},
|
||||
addFriends ({ rootState, commit }, fetchBy) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const user = rootState.users.usersObject[fetchBy]
|
||||
|
@ -263,6 +301,8 @@ const users = {
|
|||
const user = data
|
||||
// user.credentials = userCredentials
|
||||
user.credentials = accessToken
|
||||
user.blockIds = []
|
||||
user.muteIds = []
|
||||
commit('setCurrentUser', user)
|
||||
commit('addNewUsers', [user])
|
||||
|
||||
|
@ -279,11 +319,8 @@ const users = {
|
|||
// Start getting fresh posts.
|
||||
store.dispatch('startFetching', { timeline: 'friends' })
|
||||
|
||||
// Get user mutes and follower info
|
||||
store.rootState.api.backendInteractor.fetchMutes().then((mutedUsers) => {
|
||||
each(mutedUsers, (user) => { user.muted = true })
|
||||
store.commit('addNewUsers', mutedUsers)
|
||||
})
|
||||
// Get user mutes
|
||||
store.dispatch('fetchMutes')
|
||||
|
||||
// Fetch our friends
|
||||
store.rootState.api.backendInteractor.fetchFriends({ id: user.id })
|
||||
|
|
|
@ -18,6 +18,7 @@ const MENTIONS_URL = '/api/statuses/mentions.json'
|
|||
const DM_TIMELINE_URL = '/api/statuses/dm_timeline.json'
|
||||
const FOLLOWERS_URL = '/api/statuses/followers.json'
|
||||
const FRIENDS_URL = '/api/statuses/friends.json'
|
||||
const BLOCKS_URL = '/api/statuses/blocks.json'
|
||||
const FOLLOWING_URL = '/api/friendships/create.json'
|
||||
const UNFOLLOWING_URL = '/api/friendships/destroy.json'
|
||||
const QVITTER_USER_PREF_URL = '/api/qvitter/set_profile_pref.json'
|
||||
|
@ -519,6 +520,17 @@ const fetchMutes = ({credentials}) => {
|
|||
}).then((data) => data.json())
|
||||
}
|
||||
|
||||
const fetchBlocks = ({page, credentials}) => {
|
||||
return fetch(BLOCKS_URL, {
|
||||
headers: authHeaders(credentials)
|
||||
}).then((data) => {
|
||||
if (data.ok) {
|
||||
return data.json()
|
||||
}
|
||||
throw new Error('Error fetching blocks', data)
|
||||
})
|
||||
}
|
||||
|
||||
const suggestions = ({credentials}) => {
|
||||
return fetch(SUGGESTIONS_URL, {
|
||||
headers: authHeaders(credentials)
|
||||
|
@ -560,6 +572,7 @@ const apiService = {
|
|||
fetchAllFollowing,
|
||||
setUserMute,
|
||||
fetchMutes,
|
||||
fetchBlocks,
|
||||
register,
|
||||
getCaptcha,
|
||||
updateAvatar,
|
||||
|
|
|
@ -63,6 +63,7 @@ const backendInteractorService = (credentials) => {
|
|||
}
|
||||
|
||||
const fetchMutes = () => apiService.fetchMutes({credentials})
|
||||
const fetchBlocks = (params) => apiService.fetchBlocks({credentials, ...params})
|
||||
const fetchFollowRequests = () => apiService.fetchFollowRequests({credentials})
|
||||
|
||||
const getCaptcha = () => apiService.getCaptcha()
|
||||
|
@ -94,6 +95,7 @@ const backendInteractorService = (credentials) => {
|
|||
startFetching,
|
||||
setUserMute,
|
||||
fetchMutes,
|
||||
fetchBlocks,
|
||||
register,
|
||||
getCaptcha,
|
||||
updateAvatar,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue