refs #772 Accept/Reject follow requests
This commit is contained in:
parent
8c283f949c
commit
1ee9013faf
|
@ -62,6 +62,8 @@
|
|||
"notification": "Notification",
|
||||
"mention": "Mention",
|
||||
"favourite": "Favourite",
|
||||
"follow_requests": "Follow Requests",
|
||||
"direct_messages": "Direct Messages",
|
||||
"local": "Local timeline",
|
||||
"public": "Public timeline",
|
||||
"hashtag": "Hashtag",
|
||||
|
@ -299,6 +301,10 @@
|
|||
"followers": "Followers"
|
||||
}
|
||||
},
|
||||
"follow_requests": {
|
||||
"accept": "Accept",
|
||||
"reject": "Reject"
|
||||
},
|
||||
"hashtag": {
|
||||
"tag_name": "Tag name",
|
||||
"delete_tag": "Delete tag",
|
||||
|
@ -338,6 +344,8 @@
|
|||
"timeline_fetch_error": "Failed to fetch timeline",
|
||||
"notification_fetch_error": "Failed to fetch notification",
|
||||
"favourite_fetch_error": "Failed to fetch favorite",
|
||||
"follow_request_accept_error": "Failed to accept the request",
|
||||
"follow_reuqest_reject_error": "failed to reject the request",
|
||||
"start_streaming_error": "Failed to start streaming",
|
||||
"attach_error": "Could not attach the file",
|
||||
"authorize_duplicate_error": "Can not login the same account of the same domain",
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<div id="follow-requests">
|
||||
<template v-for="account in requests">
|
||||
<user :user="account" :request="true" @acceptRequest="accept" @rejectRequest="reject"></user>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import User from '@/components/molecules/User'
|
||||
|
||||
export default {
|
||||
name: 'folllow-requests',
|
||||
components: { User },
|
||||
computed: {
|
||||
...mapState('TimelineSpace/Contents/FollowRequests', {
|
||||
requests: state => state.requests
|
||||
})
|
||||
},
|
||||
async mounted() {
|
||||
await this.initialize()
|
||||
},
|
||||
methods: {
|
||||
async initialize() {
|
||||
await this.$store.dispatch('TimelineSpace/Contents/FollowRequests/fetchRequests').catch(_ => {
|
||||
this.$message({
|
||||
message: this.$t('message.timeline_fetch_error'),
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
accept(account) {
|
||||
this.$store.dispatch('TimelineSpace/Contents/FollowRequests/acceptRequest', account).catch(_ => {
|
||||
this.$message({
|
||||
message: this.$t('message.follow_request_accept_error'),
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
reject(account) {
|
||||
this.$store.dispatch('TimelineSpace/Contents/FollowRequests/rejectRequest', account).catch(_ => {
|
||||
this.$message({
|
||||
message: this.$t('message.follow_request_reject_error'),
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scorped></style>
|
|
@ -115,6 +115,9 @@ export default {
|
|||
case 'mentions':
|
||||
this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.mention'))
|
||||
break
|
||||
case 'follow-requests':
|
||||
this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.follow_requests'))
|
||||
break
|
||||
case 'local':
|
||||
this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.local'))
|
||||
break
|
||||
|
@ -134,7 +137,7 @@ export default {
|
|||
this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.lists'))
|
||||
break
|
||||
case 'direct-messages':
|
||||
this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', 'Direct Messages')
|
||||
this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.direct_messages'))
|
||||
break
|
||||
case 'edit-list':
|
||||
this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.members'))
|
||||
|
|
|
@ -61,7 +61,12 @@
|
|||
<span>{{ $t('side_menu.direct') }}</span>
|
||||
<el-badge is-dot :hidden="!unreadDirectMessagesTimeline"> </el-badge>
|
||||
</el-menu-item>
|
||||
<el-menu-item v-if="unreadFollowRequests" :index="`/${id()}/mentions`" role="menuitem" :title="$t('side_menu.follow_requests')">
|
||||
<el-menu-item
|
||||
v-if="unreadFollowRequests"
|
||||
:index="`/${id()}/follow-requests`"
|
||||
role="menuitem"
|
||||
:title="$t('side_menu.follow_requests')"
|
||||
>
|
||||
<icon name="users"></icon>
|
||||
<span>{{ $t('side_menu.follow_requests') }}</span>
|
||||
<el-badge is-dot></el-badge>
|
||||
|
|
|
@ -1,34 +1,51 @@
|
|||
<template>
|
||||
<div class="user" @click="openUser(user)" aria-label="user">
|
||||
<div class="icon" role="presentation">
|
||||
<FailoverImg :src="user.avatar" :alt="`Avatar of ${user.username}`" />
|
||||
</div>
|
||||
<div class="name">
|
||||
<div class="username">
|
||||
<bdi v-html="username(user)"></bdi>
|
||||
<div class="user" @click="openUser(user)" aria-label="user">
|
||||
<div class="icon" role="presentation">
|
||||
<FailoverImg :src="user.avatar" :alt="`Avatar of ${user.username}`" />
|
||||
</div>
|
||||
<div class="acct">
|
||||
@{{ user.acct }}
|
||||
<div class="name">
|
||||
<div class="username">
|
||||
<bdi v-html="username(user)"></bdi>
|
||||
</div>
|
||||
<div class="acct">@{{ user.acct }}</div>
|
||||
</div>
|
||||
<div class="tool" v-if="remove">
|
||||
<el-button type="text" @click.stop.prevent="removeAccount(user)">
|
||||
<icon name="times"></icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="tool" v-if="relationship">
|
||||
<el-button
|
||||
v-if="relationship.following"
|
||||
class="unfollow"
|
||||
type="text"
|
||||
@click.stop.prevent="unfollowAccount(user)"
|
||||
:title="$t('side_bar.account_profile.unfollow')"
|
||||
>
|
||||
<icon name="user-times"></icon>
|
||||
</el-button>
|
||||
<el-button v-else-if="relationship.requested" class="requested" type="text" :title="$t('side_bar.account_profile.follow_requested')">
|
||||
<icon name="hourglass"></icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else-if="!relationship.following"
|
||||
class="follow"
|
||||
type="text"
|
||||
@click.stop.prevent="followAccount(user)"
|
||||
:title="$t('side_bar.account_profile.follow')"
|
||||
>
|
||||
<icon name="user-plus"></icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="tool" v-else-if="request">
|
||||
<el-button class="accept" type="text" @click.stop.prevent="acceptRequest(user)" :title="$t('follow_requests.accept')">
|
||||
<icon name="check"></icon>
|
||||
</el-button>
|
||||
<el-button class="reject" type="text" @click.stop.prevent="rejectRequest(user)" :tilte="$t('follow_requests.reject')">
|
||||
<icon name="times"></icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool" v-if="remove">
|
||||
<el-button type="text" @click.stop.prevent="removeAccount(user)">
|
||||
<icon name="times"></icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="tool" v-if="relationship">
|
||||
<el-button v-if="relationship.following" class="unfollow" type="text" @click.stop.prevent="unfollowAccount(user)" :title="$t('side_bar.account_profile.unfollow')">
|
||||
<icon name="user-times"></icon>
|
||||
</el-button>
|
||||
<el-button v-else-if="relationship.requested" class="requested" type="text" :title="$t('side_bar.account_profile.follow_requested')">
|
||||
<icon name="hourglass"></icon>
|
||||
</el-button>
|
||||
<el-button v-else-if="!relationship.following" class="follow" type="text" @click.stop.prevent="followAccount(user)" :title="$t('side_bar.account_profile.follow')">
|
||||
<icon name="user-plus"></icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -52,29 +69,39 @@ export default {
|
|||
relationship: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
request: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
username (account) {
|
||||
username(account) {
|
||||
if (account.display_name !== '') {
|
||||
return emojify(account.display_name, account.emojis)
|
||||
} else {
|
||||
return account.username
|
||||
}
|
||||
},
|
||||
openUser (account) {
|
||||
openUser(account) {
|
||||
this.$store.dispatch('TimelineSpace/Contents/SideBar/openAccountComponent')
|
||||
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/changeAccount', account)
|
||||
this.$store.commit('TimelineSpace/Contents/SideBar/changeOpenSideBar', true)
|
||||
},
|
||||
removeAccount (account) {
|
||||
removeAccount(account) {
|
||||
this.$emit('removeAccount', account)
|
||||
},
|
||||
unfollowAccount (account) {
|
||||
unfollowAccount(account) {
|
||||
this.$emit('unfollowAccount', account)
|
||||
},
|
||||
followAccount (account) {
|
||||
followAccount(account) {
|
||||
this.$emit('followAccount', account)
|
||||
},
|
||||
acceptRequest(account) {
|
||||
this.$emit('acceptRequest', account)
|
||||
},
|
||||
rejectRequest(account) {
|
||||
this.$emit('rejectRequest', account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -151,6 +178,11 @@ export default {
|
|||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.accept,
|
||||
.reject {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -14,7 +14,7 @@ const router = new Router({
|
|||
path: '/authorize',
|
||||
name: 'authorize',
|
||||
component: require('@/components/Authorize').default,
|
||||
props: (route) => ({ url: route.query.url })
|
||||
props: route => ({ url: route.query.url })
|
||||
},
|
||||
{
|
||||
path: '/preferences/',
|
||||
|
@ -87,6 +87,11 @@ const router = new Router({
|
|||
name: 'mentions',
|
||||
component: require('@/components/TimelineSpace/Contents/Mentions').default
|
||||
},
|
||||
{
|
||||
path: 'follow-requests',
|
||||
name: 'follow-requests',
|
||||
component: require('@/components/TimelineSpace/Contents/FollowRequests').default
|
||||
},
|
||||
{
|
||||
path: 'favourites',
|
||||
name: 'favourites',
|
||||
|
|
|
@ -8,6 +8,7 @@ import Search, { SearchModuleState } from './Contents/Search'
|
|||
import Lists from './Contents/Lists'
|
||||
import Hashtag, { HashtagModuleState } from './Contents/Hashtag'
|
||||
import DirectMessages, { DirectMessagesState } from './Contents/DirectMessages'
|
||||
import FollowRequests, { FollowRequestsState } from './Contents/FollowRequests'
|
||||
import Mentions, { MentionsState } from './Contents/Mentions'
|
||||
import { Module } from 'vuex'
|
||||
import { RootState } from '@/store'
|
||||
|
@ -15,16 +16,17 @@ import { RootState } from '@/store'
|
|||
export interface ContentsState {}
|
||||
|
||||
export interface ContentsModuleState extends ContentsState {
|
||||
SideBar: SideBarModuleState,
|
||||
Home: HomeState,
|
||||
Notifications: NotificationsState,
|
||||
Mentions: MentionsState,
|
||||
DirectMessages: DirectMessagesState,
|
||||
Favourites: FavouritesState,
|
||||
Local: LocalState,
|
||||
Public: PublicState,
|
||||
Search: SearchModuleState,
|
||||
SideBar: SideBarModuleState
|
||||
Home: HomeState
|
||||
Notifications: NotificationsState
|
||||
Mentions: MentionsState
|
||||
DirectMessages: DirectMessagesState
|
||||
Favourites: FavouritesState
|
||||
Local: LocalState
|
||||
Public: PublicState
|
||||
Search: SearchModuleState
|
||||
Hashtag: HashtagModuleState
|
||||
FollowRequests: FollowRequestsState
|
||||
}
|
||||
|
||||
const state = (): ContentsState => ({})
|
||||
|
@ -43,7 +45,8 @@ const Contents: Module<ContentsState, RootState> = {
|
|||
Public,
|
||||
Search,
|
||||
Lists,
|
||||
Hashtag
|
||||
Hashtag,
|
||||
FollowRequests
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
import Mastodon, { Account, Response } from 'megalodon'
|
||||
import { Module, MutationTree, ActionTree } from 'vuex'
|
||||
import { RootState } from '@/store'
|
||||
|
||||
export interface FollowRequestsState {
|
||||
requests: Array<Account>
|
||||
}
|
||||
|
||||
const state = (): FollowRequestsState => ({
|
||||
requests: []
|
||||
})
|
||||
|
||||
export const MUTATION_TYPES = {
|
||||
UPDATE_REQUESTS: 'updateRequests'
|
||||
}
|
||||
|
||||
const mutations: MutationTree<FollowRequestsState> = {
|
||||
[MUTATION_TYPES.UPDATE_REQUESTS]: (state, accounts: Array<Account>) => {
|
||||
state.requests = accounts
|
||||
}
|
||||
}
|
||||
|
||||
const actions: ActionTree<FollowRequestsState, RootState> = {
|
||||
fetchRequests: async ({ commit, rootState }): Promise<Array<Account>> => {
|
||||
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
|
||||
const res: Response<Array<Account>> = await client.get<Array<Account>>('/follow_requests')
|
||||
commit(MUTATION_TYPES.UPDATE_REQUESTS, res.data)
|
||||
return res.data
|
||||
},
|
||||
acceptRequest: async ({ dispatch, rootState }, user: Account) => {
|
||||
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
|
||||
const res: Response<{}> = await client.post<{}>(`/follow_requests/${user.id}/authorize`)
|
||||
dispatch('fetchRequests')
|
||||
dispatch('TimelineSpace/SideMenu/fetchFollowRequests', rootState.TimelineSpace.account, { root: true })
|
||||
return res.data
|
||||
},
|
||||
rejectRequest: async ({ dispatch, rootState }, user: Account) => {
|
||||
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
|
||||
const res: Response<{}> = await client.post<{}>(`/follow_requests/${user.id}/reject`)
|
||||
dispatch('fetchRequests')
|
||||
dispatch('TimelineSpace/SideMenu/fetchFollowRequests', rootState.TimelineSpace.account, { root: true })
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
|
||||
const FollowRequests: Module<FollowRequestsState, RootState> = {
|
||||
namespaced: true,
|
||||
state: state,
|
||||
mutations: mutations,
|
||||
actions: actions
|
||||
}
|
||||
|
||||
export default FollowRequests
|
Loading…
Reference in New Issue