Compare commits

...

2 Commits

Author SHA1 Message Date
Natty 4ea5d7c106
Frontend: Follow request cleanup
ci/woodpecker/push/ociImagePush Pipeline was successful Details
2023-09-08 19:09:19 +02:00
Natty 1b87a57b8c
Frontend: Removed accidentally copied code 2023-09-08 03:35:22 +02:00
6 changed files with 132 additions and 142 deletions

View File

@ -3,6 +3,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"watch": "pnpm vite build --watch --mode development", "watch": "pnpm vite build --watch --mode development",
"watchRebuild": "pnpm vite build --watch",
"build": "pnpm vite build", "build": "pnpm vite build",
"format": "pnpm prettier --write '**/*.vue'" "format": "pnpm prettier --write '**/*.vue'"
}, },

View File

@ -0,0 +1,84 @@
<template>
<template v-if="waitIncoming">
<i class="ph-circle-notch ph-bold ph-lg fa-pulse ph-fw ph-lg"></i>
</template>
<template v-else>
<button
class="_textButton"
:disabled="waitIncoming"
@click.stop="accept(user)"
>
<i class="ph-check ph-bold ph-lg"></i>
<span class="follow-approve-label">
{{ i18n.ts.accept }}
</span>
</button>
|
<button
class="_textButton"
:disabled="waitIncoming"
@click.stop="reject(user)"
>
<i class="ph-x ph-bold ph-lg"></i>
<span class="follow-approve-label">
{{ i18n.ts.reject }}
</span>
</button>
</template>
</template>
<script lang="ts" setup>
import { onBeforeUnmount, onMounted } from "vue";
import type * as Misskey from "calckey-js";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { useRouter } from "@/router";
import { stream } from "@/stream";
import { globalEvents } from "@/events";
const router = useRouter();
const emit = defineEmits(["refresh"]);
const props = defineProps<{
user: Misskey.entities.User;
}>();
let state = $ref(i18n.ts.processing);
const connection = stream.useChannel("main");
let waitIncoming = $ref(false);
function accept(user: Misskey.entities.User) {
waitIncoming = true;
os.api("following/requests/accept", { userId: user.id }).then(() => {
globalEvents.emit("followeeProcessed", user);
});
}
function reject(user: Misskey.entities.User) {
waitIncoming = true;
os.api("following/requests/reject", { userId: user.id }).then(() => {
globalEvents.emit("followeeProcessed", user);
});
}
function onFolloweeChange(user: Misskey.entities.User) {
if (user.id === props.user.id) {
emit("refresh");
}
}
onMounted(() => {
globalEvents.on("followeeProcessed", () => onFolloweeChange(props.user));
});
onBeforeUnmount(() => {
globalEvents.off("followeeProcessed", () => onFolloweeChange(props.user));
});
</script>
<style lang="scss" scoped>
.follow-approve-label {
padding-left: 0.25em;
}
</style>

View File

@ -7,47 +7,6 @@
> >
<i class="ph-dots-three-outline ph-bold ph-lg"></i> <i class="ph-dots-three-outline ph-bold ph-lg"></i>
</button> </button>
<span
class="follow-menu"
:class="{
large,
full,
}"
v-if="
$i != null && $i.id != user.id && user.hasPendingFollowRequestToYou
"
>
<span v-if="full">
{{ i18n.ts.followRequestYou }}
</span>
<span v-else>
<i
class="ph-hand-waving ph-bold ph-lg"
:aria-label="i18n.ts.followRequestYou"
></i>
</span>
<template v-if="waitIncoming">
<i class="ph-circle-notch ph-bold ph-lg fa-pulse"></i>
</template>
<template v-else>
<button
class="_button follow-incoming"
:disabled="waitIncoming"
@click.stop="accept(user)"
v-tooltip="i18n.ts.accept"
>
<i class="ph-check ph-bold ph-lg"></i>
</button>
<button
class="_button follow-incoming"
:disabled="waitIncoming"
@click.stop="reject(user)"
v-tooltip="i18n.ts.reject"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
</template>
</span>
<button <button
v-if="$i != null && $i.id != user.id" v-if="$i != null && $i.id != user.id"
class="kpoogebi _button follow-button" class="kpoogebi _button follow-button"
@ -136,23 +95,8 @@ let hasPendingFollowRequestFromYou = $ref(
props.user.hasPendingFollowRequestFromYou props.user.hasPendingFollowRequestFromYou
); );
let wait = $ref(false); let wait = $ref(false);
let waitIncoming = $ref(false);
const connection = stream.useChannel("main"); const connection = stream.useChannel("main");
function accept(user) {
waitIncoming = true;
os.api("following/requests/accept", { userId: user.id }).then(() => {
emit("refresh");
});
}
function reject(user) {
waitIncoming = true;
os.api("following/requests/reject", { userId: user.id }).then(() => {
emit("refresh");
});
}
if (props.user.isFollowing == null) { if (props.user.isFollowing == null) {
os.api("users/show", { os.api("users/show", {
userId: props.user.id, userId: props.user.id,
@ -242,55 +186,6 @@ onBeforeUnmount(() => {
height: 2em; height: 2em;
vertical-align: middle; vertical-align: middle;
} }
.follow-menu {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: var(--accent);
border: solid 1px var(--accent);
padding: 0;
font-size: 16px;
height: 2em;
border-radius: 100px;
background: var(--bg);
vertical-align: middle;
&.full {
padding: 0.2em 0.7em;
font-size: 14px;
}
&.large {
font-size: 16px;
height: 38px;
padding: 0 12px 0 16px;
}
&.follow-incoming {
margin: 0 0.5em;
border-inline-start: solid 1px var(--accent);
&.active {
color: var(--fgOnAccent);
background: var(--accent);
&:hover {
background: var(--accentLighten);
border-color: var(--accentLighten);
}
&:active {
background: var(--accentDarken);
border-color: var(--accentDarken);
}
}
}
}
.follow-button { .follow-button {
position: relative; position: relative;
display: inline-flex; display: inline-flex;

View File

@ -220,8 +220,9 @@
:user="notification.user" :user="notification.user"
:full="true" :full="true"
:hideMenu="true" :hideMenu="true"
/></div />
></span> </div>
</span>
<span <span
v-if="notification.type === 'followRequestAccepted'" v-if="notification.type === 'followRequestAccepted'"
class="text" class="text"
@ -234,15 +235,12 @@
style="opacity: 0.7" style="opacity: 0.7"
>{{ i18n.ts.receiveFollowRequest }} >{{ i18n.ts.receiveFollowRequest }}
<div v-if="full && !followRequestDone"> <div v-if="full && !followRequestDone">
<button class="_textButton" @click="acceptFollowRequest()"> <MkFollowApproveButton
{{ i18n.ts.accept }} :user="notification.user"
</button> @refresh="followRequestDone = true"
| />
<button class="_textButton" @click="rejectFollowRequest()"> </div>
{{ i18n.ts.reject }} </span>
</button>
</div></span
>
<span <span
v-if="notification.type === 'groupInvited'" v-if="notification.type === 'groupInvited'"
class="text" class="text"
@ -263,8 +261,8 @@
> >
{{ i18n.ts.reject }} {{ i18n.ts.reject }}
</button> </button>
</div></span </div>
> </span>
<span v-if="notification.type === 'app'" class="text"> <span v-if="notification.type === 'app'" class="text">
<Mfm :text="notification.body" :nowrap="!full" /> <Mfm :text="notification.body" :nowrap="!full" />
</span> </span>
@ -273,7 +271,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch } from "vue"; import { onMounted, onUnmounted, ref, watch } from "vue";
import * as misskey from "calckey-js"; import * as misskey from "calckey-js";
import XReactionIcon from "@/components/MkReactionIcon.vue"; import XReactionIcon from "@/components/MkReactionIcon.vue";
import MkFollowButton from "@/components/MkFollowButton.vue"; import MkFollowButton from "@/components/MkFollowButton.vue";
@ -287,6 +285,7 @@ import { stream } from "@/stream";
import { useTooltip } from "@/scripts/use-tooltip"; import { useTooltip } from "@/scripts/use-tooltip";
import { defaultStore } from "@/store"; import { defaultStore } from "@/store";
import { instance } from "@/instance"; import { instance } from "@/instance";
import MkFollowApproveButton from "@/components/MkFollowApproveButton.vue";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -300,6 +299,7 @@ const props = withDefaults(
} }
); );
const emit = defineEmits(["refresh"]);
const elRef = ref<HTMLElement>(null); const elRef = ref<HTMLElement>(null);
const reactionRef = ref(null); const reactionRef = ref(null);
@ -342,16 +342,6 @@ onUnmounted(() => {
const followRequestDone = ref(false); const followRequestDone = ref(false);
const groupInviteDone = ref(false); const groupInviteDone = ref(false);
const acceptFollowRequest = () => {
followRequestDone.value = true;
os.api("following/requests/accept", { userId: props.notification.user.id });
};
const rejectFollowRequest = () => {
followRequestDone.value = true;
os.api("following/requests/reject", { userId: props.notification.user.id });
};
const acceptGroupInvitation = () => { const acceptGroupInvitation = () => {
groupInviteDone.value = true; groupInviteDone.value = true;
os.apiWithDialog("users/groups/invitations/accept", { os.apiWithDialog("users/groups/invitations/accept", {

View File

@ -80,30 +80,44 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed } from "vue"; import { computed, onBeforeUnmount, onMounted, ref } from "vue";
import MkPagination from "@/components/MkPagination.vue"; import MkPagination from "@/components/MkPagination.vue";
import { userPage, acct } from "@/filters/user"; import { acct, userPage } from "@/filters/user";
import * as os from "@/os"; import * as os from "@/os";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
import { $i } from "@/account"; import { $i } from "@/account";
import { globalEvents } from "@/events";
const paginationComponent = ref<InstanceType<typeof MkPagination>>(); const paginationComponent = ref<InstanceType<typeof MkPagination>>();
const pagination = { const pagination = {
endpoint: "following/requests/list" as const, endpoint: "following/requests/list" as const,
limit: 10, limit: 10,
noPaging: true,
}; };
onMounted(() => {
globalEvents.on("followeeProcessed", () =>
paginationComponent.value.reload()
);
});
onBeforeUnmount(() => {
globalEvents.off("followeeProcessed", () =>
paginationComponent.value.reload()
);
});
function accept(user) { function accept(user) {
os.api("following/requests/accept", { userId: user.id }).then(() => { os.api("following/requests/accept", { userId: user.id }).then(() => {
paginationComponent.value.reload(); globalEvents.emit("followeeProcessed", user);
}); });
} }
function reject(user) { function reject(user) {
os.api("following/requests/reject", { userId: user.id }).then(() => { os.api("following/requests/reject", { userId: user.id }).then(() => {
paginationComponent.value.reload(); globalEvents.emit("followeeProcessed", user);
}); });
} }

View File

@ -69,6 +69,20 @@
class="followed" class="followed"
>{{ i18n.ts.followsYou }}</span >{{ i18n.ts.followsYou }}</span
> >
<span
v-if="
$i &&
$i.id != user.id &&
user.hasPendingFollowRequestToYou
"
class="followed"
>{{ i18n.ts.followRequestYou }}:
<MkFollowApproveButton
:user="user"
@refresh="emit('refresh')"
class="koudoku"
/>
</span>
</div> </div>
<div class="bottom"> <div class="bottom">
<span class="username" <span class="username"
@ -369,7 +383,7 @@ import { getScrollPosition } from "@/scripts/scroll";
import { userPage } from "@/filters/user"; import { userPage } from "@/filters/user";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { $i } from "@/account"; import { $i } from "@/account";
import * as os from "@/os"; import MkFollowApproveButton from "@/components/MkFollowApproveButton.vue";
const XPhotos = defineAsyncComponent(() => import("./index.photos.vue")); const XPhotos = defineAsyncComponent(() => import("./index.photos.vue"));
const XActivity = defineAsyncComponent(() => import("./index.activity.vue")); const XActivity = defineAsyncComponent(() => import("./index.activity.vue"));
@ -382,14 +396,6 @@ const props = withDefaults(
{} {}
); );
function accept(user) {
os.api("following/requests/accept", { userId: user.id });
}
function reject(user) {
os.api("following/requests/reject", { userId: user.id }).then();
}
let parallaxAnimationId = $ref<null | number>(null); let parallaxAnimationId = $ref<null | number>(null);
let narrow = $ref<null | boolean>(null); let narrow = $ref<null | boolean>(null);
let rootEl = $ref<null | HTMLElement>(null); let rootEl = $ref<null | HTMLElement>(null);