Merge branch 'feat/unreply_following_request_follower_list' into 'develop'
feat: sent follow request list api and user interface Co-authored-by: laozhoubuluo <laozhoubuluo@gmail.com> Closes #10856 See merge request firefish/firefish!10672
This commit is contained in:
commit
97a871f1a6
10 changed files with 234 additions and 0 deletions
|
@ -4,6 +4,7 @@ Breaking changes are indicated by the :warning: icon.
|
|||
|
||||
## Unreleased
|
||||
|
||||
- Added `following/requests/sent` endpoint for added Sent Following Requests List Feature.
|
||||
- The following endpoints are added:
|
||||
- `reply-mute/create`
|
||||
- `reply-mute/delete`
|
||||
|
|
|
@ -109,6 +109,7 @@ defaultNoteVisibility: "Default visibility"
|
|||
follow: "Follow"
|
||||
followRequest: "Follow Request"
|
||||
followRequests: "Follow requests"
|
||||
sentFollowRequests: "Sent follow requests"
|
||||
unfollow: "Unfollow"
|
||||
followRequestPending: "Follow request pending"
|
||||
enterEmoji: "Enter an emoji"
|
||||
|
@ -534,6 +535,7 @@ existingAccount: "Existing account"
|
|||
regenerate: "Regenerate"
|
||||
fontSize: "Font size"
|
||||
noFollowRequests: "You don't have any pending follow requests"
|
||||
noSentFollowRequests: "You don't have any sent follow requests"
|
||||
openImageInNewTab: "Open images in new tab"
|
||||
dashboard: "Dashboard"
|
||||
local: "Local"
|
||||
|
|
|
@ -91,6 +91,7 @@ defaultNoteVisibility: "默认可见性"
|
|||
follow: "关注"
|
||||
followRequest: "关注请求"
|
||||
followRequests: "关注请求"
|
||||
sentFollowRequests: "待回应的关注请求"
|
||||
unfollow: "取消关注"
|
||||
followRequestPending: "关注请求待批准"
|
||||
enterEmoji: "输入表情符号"
|
||||
|
@ -470,6 +471,7 @@ existingAccount: "现有的账号"
|
|||
regenerate: "重新生成"
|
||||
fontSize: "字体大小"
|
||||
noFollowRequests: "没有待批准的关注申请"
|
||||
noSentFollowRequests: "没有待回应的关注请求"
|
||||
openImageInNewTab: "在新标签页中打开图片"
|
||||
dashboard: "管理面板"
|
||||
local: "本地"
|
||||
|
|
|
@ -91,6 +91,7 @@ defaultNoteVisibility: "預設可見性"
|
|||
follow: "追隨"
|
||||
followRequest: "追隨請求"
|
||||
followRequests: "追隨請求"
|
||||
sentFollowRequests: "待回應的追隨請求"
|
||||
unfollow: "取消追隨"
|
||||
followRequestPending: "追隨許可批准中"
|
||||
enterEmoji: "輸入表情符號"
|
||||
|
@ -469,6 +470,7 @@ existingAccount: "現有帳戶"
|
|||
regenerate: "再生"
|
||||
fontSize: "字體大小"
|
||||
noFollowRequests: "沒有要求跟隨您的申請"
|
||||
noSentFollowRequests: "沒有待回應的跟隨申請"
|
||||
openImageInNewTab: "於新分頁中開啟圖片"
|
||||
dashboard: "儀表板"
|
||||
local: "本地"
|
||||
|
|
|
@ -144,6 +144,7 @@ import * as ep___following_invalidate from "./endpoints/following/invalidate.js"
|
|||
import * as ep___following_requests_accept from "./endpoints/following/requests/accept.js";
|
||||
import * as ep___following_requests_cancel from "./endpoints/following/requests/cancel.js";
|
||||
import * as ep___following_requests_list from "./endpoints/following/requests/list.js";
|
||||
import * as ep___following_requests_sent from "./endpoints/following/requests/sent.js";
|
||||
import * as ep___following_requests_reject from "./endpoints/following/requests/reject.js";
|
||||
import * as ep___gallery_featured from "./endpoints/gallery/featured.js";
|
||||
import * as ep___gallery_popular from "./endpoints/gallery/popular.js";
|
||||
|
@ -492,6 +493,7 @@ const eps = [
|
|||
["following/requests/accept", ep___following_requests_accept],
|
||||
["following/requests/cancel", ep___following_requests_cancel],
|
||||
["following/requests/list", ep___following_requests_list],
|
||||
["following/requests/sent", ep___following_requests_sent],
|
||||
["following/requests/reject", ep___following_requests_reject],
|
||||
["gallery/featured", ep___gallery_featured],
|
||||
["gallery/popular", ep___gallery_popular],
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { FollowRequests } from "@/models/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["following", "users"],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: "read:following",
|
||||
|
||||
res: {
|
||||
type: "array",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
items: {
|
||||
type: "object",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: "string",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
format: "id",
|
||||
},
|
||||
follower: {
|
||||
type: "object",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
ref: "UserLite",
|
||||
},
|
||||
followee: {
|
||||
type: "object",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
ref: "UserLite",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const reqs = await FollowRequests.findBy({
|
||||
followerId: user.id,
|
||||
});
|
||||
|
||||
return await Promise.all(reqs.map((req) => FollowRequests.pack(req)));
|
||||
});
|
160
packages/client/src/pages/follow-requests-sent.vue
Normal file
160
packages/client/src/pages/follow-requests-sent.vue
Normal file
|
@ -0,0 +1,160 @@
|
|||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader /></template>
|
||||
<MkSpacer :content-max="800">
|
||||
<MkPagination ref="paginationComponent" :pagination="pagination">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img
|
||||
src="/static-assets/badges/info.webp"
|
||||
aria-label="none"
|
||||
class="_ghost"
|
||||
/>
|
||||
<div>{{ i18n.ts.noSentFollowRequests }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="{ items }">
|
||||
<div class="mk-follow-requests">
|
||||
<div
|
||||
v-for="req in items"
|
||||
:key="req.id"
|
||||
class="user _panel"
|
||||
>
|
||||
<MkAvatar
|
||||
class="avatar"
|
||||
:user="req.followee"
|
||||
:show-indicator="true"
|
||||
disable-link
|
||||
/>
|
||||
<div class="body">
|
||||
<div class="name">
|
||||
<MkA
|
||||
v-user-preview="req.followee.id"
|
||||
class="name"
|
||||
:to="userPage(req.followee)"
|
||||
><MkUserName :user="req.followee"
|
||||
/></MkA>
|
||||
<p class="acct">
|
||||
@{{ acct.toString(req.followee) }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
v-if="req.followee.description"
|
||||
class="description"
|
||||
:title="req.followee.description"
|
||||
>
|
||||
<Mfm
|
||||
:text="req.followee.description"
|
||||
:is-note="false"
|
||||
:author="req.followee"
|
||||
:i="$i"
|
||||
:custom-emojis="req.followee.emojis"
|
||||
:plain="true"
|
||||
:nowrap="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</MkPagination>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import MkPagination from "@/components/MkPagination.vue";
|
||||
import { acct } from "firefish-js";
|
||||
import { userPage } from "@/filters/user";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
import { $i } from "@/reactiveAccount";
|
||||
import icon from "@/scripts/icon";
|
||||
|
||||
const paginationComponent = ref<InstanceType<typeof MkPagination>>();
|
||||
|
||||
const pagination = {
|
||||
endpoint: "following/requests/sent" as const,
|
||||
limit: 10,
|
||||
noPaging: true,
|
||||
};
|
||||
|
||||
definePageMetadata(
|
||||
computed(() => ({
|
||||
title: i18n.ts.sentFollowRequests,
|
||||
icon: `${icon("ph-hand-waving")}`,
|
||||
})),
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mk-follow-requests {
|
||||
> .user {
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
margin: 10px 0 auto;
|
||||
|
||||
> .avatar {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
margin: 0 12px 0 0;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
> .body {
|
||||
display: flex;
|
||||
width: calc(100% - 54px);
|
||||
position: relative;
|
||||
|
||||
> .name {
|
||||
width: 45%;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> .name,
|
||||
> .acct {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
> .name {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
> .acct {
|
||||
font-size: 15px;
|
||||
line-height: 16px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
> .description {
|
||||
width: 55%;
|
||||
line-height: 42px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
opacity: 0.7;
|
||||
font-size: 14px;
|
||||
padding-right: 40px;
|
||||
padding-left: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -4,6 +4,10 @@
|
|||
i18n.ts.accountInfo
|
||||
}}</FormLink>
|
||||
|
||||
<FormLink to="/my/follow-requests/sent" class="_formBlock">{{
|
||||
i18n.ts.sentFollowRequests
|
||||
}}</FormLink>
|
||||
|
||||
<FormLink to="/registry" class="_formBlock"
|
||||
><template #icon><i :class="icon('ph-gear-six')"></i></template
|
||||
>{{ i18n.ts.registry }}</FormLink
|
||||
|
|
|
@ -587,6 +587,11 @@ export const routes = [
|
|||
component: page(() => import("./pages/follow-requests.vue")),
|
||||
loginRequired: true,
|
||||
},
|
||||
{
|
||||
path: "/my/follow-requests/sent",
|
||||
component: page(() => import("./pages/follow-requests-sent.vue")),
|
||||
loginRequired: true,
|
||||
},
|
||||
{
|
||||
path: "/my/lists/:listId",
|
||||
component: page(() => import("./pages/my-lists/list.vue")),
|
||||
|
|
|
@ -399,6 +399,7 @@ export type Endpoints = {
|
|||
"following/requests/accept": { req: { userId: User["id"] }; res: null };
|
||||
"following/requests/cancel": { req: { userId: User["id"] }; res: User };
|
||||
"following/requests/list": { req: NoParams; res: FollowRequest[] };
|
||||
"following/requests/sent": { req: NoParams; res: FollowRequest[] };
|
||||
"following/requests/reject": { req: { userId: User["id"] }; res: null };
|
||||
|
||||
// gallery
|
||||
|
|
Loading…
Reference in a new issue