forked from Mirrors/elk
feat: handle follow request (#2339)
This commit is contained in:
parent
d825a71d1f
commit
5fceb70971
6 changed files with 99 additions and 8 deletions
|
@ -19,8 +19,10 @@ cacheAccount(account)
|
||||||
overflow-hidden
|
overflow-hidden
|
||||||
:to="getAccountRoute(account)"
|
:to="getAccountRoute(account)"
|
||||||
/>
|
/>
|
||||||
<div h-full p1 shrink-0>
|
<slot>
|
||||||
<AccountFollowButton :account="account" :context="relationshipContext" />
|
<div h-full p1 shrink-0>
|
||||||
</div>
|
<AccountFollowButton :account="account" :context="relationshipContext" />
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
68
components/account/AccountFollowRequestButton.vue
Normal file
68
components/account/AccountFollowRequestButton.vue
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { mastodon } from 'masto'
|
||||||
|
|
||||||
|
const { account, ...props } = defineProps<{
|
||||||
|
account: mastodon.v1.Account
|
||||||
|
relationship?: mastodon.v1.Relationship
|
||||||
|
}>()
|
||||||
|
const relationship = $computed(() => props.relationship || useRelationship(account).value)
|
||||||
|
const { client } = $(useMasto())
|
||||||
|
|
||||||
|
async function authorizeFollowRequest() {
|
||||||
|
relationship!.requestedBy = false
|
||||||
|
relationship!.followedBy = true
|
||||||
|
try {
|
||||||
|
const newRel = await client.v1.followRequests.authorize(account.id)
|
||||||
|
Object.assign(relationship!, newRel)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
relationship!.requestedBy = true
|
||||||
|
relationship!.followedBy = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rejectFollowRequest() {
|
||||||
|
relationship!.requestedBy = false
|
||||||
|
try {
|
||||||
|
const newRel = await client.v1.followRequests.reject(account.id)
|
||||||
|
Object.assign(relationship!, newRel)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
relationship!.requestedBy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div flex gap-4>
|
||||||
|
<template v-if="relationship?.requestedBy">
|
||||||
|
<CommonTooltip :content="$t('account.authorize')" no-auto-focus>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
rounded-full text-sm p2 border-1
|
||||||
|
hover:text-green transition-colors
|
||||||
|
@click="authorizeFollowRequest"
|
||||||
|
>
|
||||||
|
<span block text-current i-ri:check-fill />
|
||||||
|
</button>
|
||||||
|
</CommonTooltip>
|
||||||
|
<CommonTooltip :content="$t('account.reject')" no-auto-focus>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
rounded-full text-sm p2 border-1
|
||||||
|
hover:text-red transition-colors
|
||||||
|
@click="rejectFollowRequest"
|
||||||
|
>
|
||||||
|
<span block text-current i-ri:close-fill />
|
||||||
|
</button>
|
||||||
|
</CommonTooltip>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span text-secondary>
|
||||||
|
{{ relationship?.followedBy ? $t('account.authorized') : $t('account.rejected') }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -109,6 +109,10 @@ const personalNoteMaxLength = 2000
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div flex flex-col>
|
<div flex flex-col>
|
||||||
|
<div v-if="relationship?.requestedBy" p-4 flex justify-between items-center bg-card>
|
||||||
|
<span text-primary font-bold>{{ $t('account.requested', [account.displayName]) }}</span>
|
||||||
|
<AccountFollowRequestButton :account="account" :relationship="relationship" />
|
||||||
|
</div>
|
||||||
<component :is="hasHeader ? 'button' : 'div'" border="b base" z-1 @click="hasHeader ? previewHeader() : undefined">
|
<component :is="hasHeader ? 'button' : 'div'" border="b base" z-1 @click="hasHeader ? previewHeader() : undefined">
|
||||||
<img h-50 height="200" w-full object-cover :src="account.header" :alt="t('account.profile_description', [account.username])">
|
<img h-50 height="200" w-full object-cover :src="account.header" :alt="t('account.profile_description', [account.username])">
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -60,12 +60,19 @@ const { notification } = defineProps<{
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="notification.type === 'follow_request'">
|
<template v-else-if="notification.type === 'follow_request'">
|
||||||
<div flex ms-4 items-center class="-top-2.5" absolute inset-ie-2 px-2>
|
<div flex px-3 py-2>
|
||||||
<div i-ri:user-shared-fill text-xl me-1 />
|
<div i-ri-user-shared-line text-xl me-3 color-blue />
|
||||||
<AccountInlineInfo :account="notification.account" me1 />
|
<AccountDisplayName
|
||||||
|
:account="notification.account"
|
||||||
|
text-primary me-1 font-bold line-clamp-1 ws-pre-wrap break-all
|
||||||
|
/>
|
||||||
|
<span me-1 ws-nowrap>
|
||||||
|
{{ $t('notification.request_to_follow') }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- TODO: accept request -->
|
<AccountCard p="s-2 e-4 b-2" hover-card :account="notification.account">
|
||||||
<AccountCard :account="notification.account" />
|
<AccountFollowRequestButton :account="notification.account" />
|
||||||
|
</AccountCard>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="notification.type === 'update'">
|
<template v-else-if="notification.type === 'update'">
|
||||||
<StatusCard :status="notification.status!" :in-notification="true" :actions="false">
|
<StatusCard :status="notification.status!" :in-notification="true" :actions="false">
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
"route_loaded": "Page {0} loaded"
|
"route_loaded": "Page {0} loaded"
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
|
"authorize": "Authorize to follow",
|
||||||
|
"authorized": "You have Authorized the request",
|
||||||
"avatar_description": "{0}'s avatar",
|
"avatar_description": "{0}'s avatar",
|
||||||
"blocked_by": "You're blocked by this user.",
|
"blocked_by": "You're blocked by this user.",
|
||||||
"blocked_domains": "Blocked domains",
|
"blocked_domains": "Blocked domains",
|
||||||
|
@ -36,7 +38,10 @@
|
||||||
"profile_description": "{0}'s profile header",
|
"profile_description": "{0}'s profile header",
|
||||||
"profile_personal_note": "Personal Note",
|
"profile_personal_note": "Personal Note",
|
||||||
"profile_unavailable": "Profile unavailable",
|
"profile_unavailable": "Profile unavailable",
|
||||||
|
"reject": "Reject to follow",
|
||||||
|
"rejected": "You have rejected the request",
|
||||||
"request_follow": "Request to follow",
|
"request_follow": "Request to follow",
|
||||||
|
"requested": "{0} has requested to follow you",
|
||||||
"unblock": "Unblock",
|
"unblock": "Unblock",
|
||||||
"unfollow": "Unfollow",
|
"unfollow": "Unfollow",
|
||||||
"unmute": "Unmute",
|
"unmute": "Unmute",
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
"route_loaded": "页面{0}已加载"
|
"route_loaded": "页面{0}已加载"
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
|
"authorize": "同意关注请求",
|
||||||
|
"authorized": "你同意了关注请求",
|
||||||
"avatar_description": "{0} 的头像",
|
"avatar_description": "{0} 的头像",
|
||||||
"blocked_by": "您已被此用户拉黑",
|
"blocked_by": "您已被此用户拉黑",
|
||||||
"blocked_domains": "已拉黑的域名",
|
"blocked_domains": "已拉黑的域名",
|
||||||
|
@ -36,7 +38,10 @@
|
||||||
"profile_description": "{0} 的个人资料头图",
|
"profile_description": "{0} 的个人资料头图",
|
||||||
"profile_personal_note": "私人备注",
|
"profile_personal_note": "私人备注",
|
||||||
"profile_unavailable": "个人资料不可见",
|
"profile_unavailable": "个人资料不可见",
|
||||||
|
"reject": "拒绝关注请求",
|
||||||
|
"rejected": "你拒绝了关注请求",
|
||||||
"request_follow": "请求关注",
|
"request_follow": "请求关注",
|
||||||
|
"requested": "{0} 向你发送了关注请求",
|
||||||
"unblock": "取消拉黑",
|
"unblock": "取消拉黑",
|
||||||
"unfollow": "取消关注",
|
"unfollow": "取消关注",
|
||||||
"unmute": "取消屏蔽",
|
"unmute": "取消屏蔽",
|
||||||
|
|
Loading…
Reference in a new issue