2020-07-09 17:24:28 +02:00
|
|
|
<template>
|
2022-07-12 10:55:28 +02:00
|
|
|
<div class="container mx-auto" v-if="discussion">
|
2022-01-10 15:19:16 +01:00
|
|
|
<breadcrumbs-nav
|
|
|
|
v-if="group"
|
|
|
|
:links="[
|
|
|
|
{
|
|
|
|
name: RouteName.MY_GROUPS,
|
2022-10-31 11:43:18 +01:00
|
|
|
text: t('My groups'),
|
2022-01-10 15:19:16 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: RouteName.GROUP,
|
|
|
|
params: { preferredUsername: usernameWithDomain(group) },
|
|
|
|
text: displayName(group),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: RouteName.DISCUSSION_LIST,
|
|
|
|
params: { preferredUsername: usernameWithDomain(group) },
|
2022-10-31 11:43:18 +01:00
|
|
|
text: t('Discussions'),
|
2022-01-10 15:19:16 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: RouteName.DISCUSSION,
|
|
|
|
params: { id: discussion.id },
|
|
|
|
text: discussion.title,
|
|
|
|
},
|
|
|
|
]"
|
|
|
|
/>
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-notification v-if="error" variant="danger">
|
2021-03-31 10:06:13 +02:00
|
|
|
{{ error }}
|
2022-07-12 10:55:28 +02:00
|
|
|
</o-notification>
|
|
|
|
<section v-if="currentActor">
|
|
|
|
<div class="flex items-center gap-2" dir="auto">
|
|
|
|
<h1 class="" v-if="discussion.title && !editTitleMode">
|
2020-07-09 17:24:28 +02:00
|
|
|
{{ discussion.title }}
|
2021-09-07 17:55:25 +02:00
|
|
|
</h1>
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-button
|
2021-09-07 17:55:25 +02:00
|
|
|
icon-right="pencil"
|
2022-07-12 10:55:28 +02:00
|
|
|
size="small"
|
2022-10-31 11:43:18 +01:00
|
|
|
:title="t('Update discussion title')"
|
2021-09-07 17:55:25 +02:00
|
|
|
v-if="
|
|
|
|
discussion.creator &&
|
|
|
|
!editTitleMode &&
|
2022-07-12 10:55:28 +02:00
|
|
|
(currentActor?.id === discussion.creator.id ||
|
2021-09-07 17:55:25 +02:00
|
|
|
isCurrentActorAGroupModerator)
|
|
|
|
"
|
|
|
|
@click="
|
|
|
|
() => {
|
2022-07-12 10:55:28 +02:00
|
|
|
newTitle = discussion?.title ?? '';
|
2021-09-07 17:55:25 +02:00
|
|
|
editTitleMode = true;
|
|
|
|
}
|
|
|
|
"
|
|
|
|
>
|
2022-07-12 10:55:28 +02:00
|
|
|
</o-button>
|
|
|
|
<o-skeleton
|
|
|
|
v-else-if="!editTitleMode && discussionLoading"
|
2021-03-31 10:06:13 +02:00
|
|
|
height="50px"
|
|
|
|
animated
|
|
|
|
/>
|
|
|
|
<form
|
2022-07-12 10:55:28 +02:00
|
|
|
v-else-if="!discussionLoading && !error"
|
2021-03-31 10:06:13 +02:00
|
|
|
@submit.prevent="updateDiscussion"
|
2022-07-12 10:55:28 +02:00
|
|
|
class="w-full"
|
2021-03-31 10:06:13 +02:00
|
|
|
>
|
2022-10-31 11:43:18 +01:00
|
|
|
<o-field :label="t('Title')" label-for="discussion-title">
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-input
|
2021-09-07 17:55:25 +02:00
|
|
|
:value="discussion.title"
|
|
|
|
v-model="newTitle"
|
|
|
|
id="discussion-title"
|
|
|
|
/>
|
2022-07-12 10:55:28 +02:00
|
|
|
</o-field>
|
|
|
|
<div class="flex gap-2 mt-2">
|
|
|
|
<o-button
|
|
|
|
variant="primary"
|
2020-11-30 10:24:11 +01:00
|
|
|
native-type="submit"
|
|
|
|
icon-right="check"
|
2022-10-31 11:43:18 +01:00
|
|
|
:title="t('Update discussion title')"
|
2020-11-30 10:24:11 +01:00
|
|
|
/>
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-button
|
2020-07-09 17:24:28 +02:00
|
|
|
@click="
|
|
|
|
() => {
|
|
|
|
editTitleMode = false;
|
|
|
|
newTitle = '';
|
|
|
|
}
|
|
|
|
"
|
2022-11-03 17:21:51 +01:00
|
|
|
outlined
|
2020-07-09 17:24:28 +02:00
|
|
|
icon-right="close"
|
2022-10-31 11:43:18 +01:00
|
|
|
:title="t('Cancel discussion title edition')"
|
2020-07-09 17:24:28 +02:00
|
|
|
/>
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-button
|
2021-03-04 17:39:50 +01:00
|
|
|
@click="openDeleteDiscussionConfirmation"
|
2022-07-12 10:55:28 +02:00
|
|
|
variant="danger"
|
2020-07-09 17:24:28 +02:00
|
|
|
native-type="button"
|
|
|
|
icon-left="delete"
|
2022-10-31 11:43:18 +01:00
|
|
|
>{{ t("Delete conversation") }}</o-button
|
2020-07-09 17:24:28 +02:00
|
|
|
>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
<discussion-comment
|
2022-08-26 16:08:58 +02:00
|
|
|
class="border rounded-md p-2 mt-4"
|
2020-07-09 17:24:28 +02:00
|
|
|
v-for="comment in discussion.comments.elements"
|
|
|
|
:key="comment.id"
|
2022-07-12 10:55:28 +02:00
|
|
|
:model-value="comment"
|
|
|
|
:current-actor="currentActor"
|
|
|
|
@update:modelValue="
|
|
|
|
(comment: IComment) =>
|
|
|
|
updateComment({
|
|
|
|
commentId: comment.id as string,
|
|
|
|
text: comment.text,
|
|
|
|
})
|
|
|
|
"
|
|
|
|
@delete-comment="(comment: IComment) => deleteComment({
|
|
|
|
commentId: comment.id as string,
|
|
|
|
})"
|
2020-07-09 17:24:28 +02:00
|
|
|
/>
|
2022-07-12 10:55:28 +02:00
|
|
|
<o-button
|
2020-07-09 17:24:28 +02:00
|
|
|
v-if="discussion.comments.elements.length < discussion.comments.total"
|
|
|
|
@click="loadMoreComments"
|
2022-10-31 11:43:18 +01:00
|
|
|
>{{ t("Fetch more") }}</o-button
|
2020-07-09 17:24:28 +02:00
|
|
|
>
|
2021-03-31 10:06:13 +02:00
|
|
|
<form @submit.prevent="reply" v-if="!error">
|
2022-10-31 11:43:18 +01:00
|
|
|
<o-field :label="t('Text')">
|
2022-07-12 10:55:28 +02:00
|
|
|
<Editor
|
|
|
|
v-model="newComment"
|
2022-10-31 11:43:18 +01:00
|
|
|
:aria-label="t('Message body')"
|
2022-07-12 10:55:28 +02:00
|
|
|
v-if="currentActor"
|
|
|
|
:currentActor="currentActor"
|
2022-10-31 11:43:18 +01:00
|
|
|
:placeholder="t('Write a new message')"
|
2022-07-12 10:55:28 +02:00
|
|
|
/>
|
|
|
|
</o-field>
|
|
|
|
<o-button
|
|
|
|
class="my-2"
|
2020-08-14 11:32:23 +02:00
|
|
|
native-type="submit"
|
|
|
|
:disabled="['<p></p>', ''].includes(newComment)"
|
2022-07-12 10:55:28 +02:00
|
|
|
variant="primary"
|
2022-10-31 11:43:18 +01:00
|
|
|
>{{ t("Reply") }}</o-button
|
2020-08-14 11:32:23 +02:00
|
|
|
>
|
2020-07-09 17:24:28 +02:00
|
|
|
</form>
|
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
</template>
|
2022-07-12 10:55:28 +02:00
|
|
|
<script lang="ts" setup>
|
2020-07-09 17:24:28 +02:00
|
|
|
import {
|
|
|
|
GET_DISCUSSION,
|
|
|
|
REPLY_TO_DISCUSSION,
|
|
|
|
UPDATE_DISCUSSION,
|
|
|
|
DELETE_DISCUSSION,
|
|
|
|
DISCUSSION_COMMENT_CHANGED,
|
|
|
|
} from "@/graphql/discussion";
|
2021-06-11 15:08:43 +02:00
|
|
|
import { IDiscussion } from "@/types/discussions";
|
2022-07-12 10:55:28 +02:00
|
|
|
import { displayName, IPerson, usernameWithDomain } from "@/types/actor";
|
2020-07-09 17:24:28 +02:00
|
|
|
import DiscussionComment from "@/components/Discussion/DiscussionComment.vue";
|
2020-08-31 12:40:30 +02:00
|
|
|
import { DELETE_COMMENT, UPDATE_COMMENT } from "@/graphql/comment";
|
2020-07-09 17:24:28 +02:00
|
|
|
import RouteName from "../../router/name";
|
|
|
|
import { IComment } from "../../types/comment.model";
|
2022-07-12 10:55:28 +02:00
|
|
|
import { ApolloCache, FetchResult, gql } from "@apollo/client/core";
|
|
|
|
import { useMutation, useQuery } from "@vue/apollo-composable";
|
|
|
|
import {
|
|
|
|
defineAsyncComponent,
|
|
|
|
onMounted,
|
|
|
|
onUnmounted,
|
|
|
|
ref,
|
|
|
|
computed,
|
|
|
|
inject,
|
|
|
|
} from "vue";
|
|
|
|
import { useHead } from "@vueuse/head";
|
|
|
|
import { useRouter } from "vue-router";
|
|
|
|
import { useCurrentActorClient } from "@/composition/apollo/actor";
|
|
|
|
import { AbsintheGraphQLError } from "@/types/errors.model";
|
|
|
|
import { useGroup } from "@/composition/apollo/group";
|
|
|
|
import { MemberRole } from "@/types/enums";
|
|
|
|
import { PERSON_MEMBERSHIPS } from "@/graphql/actor";
|
|
|
|
import { Dialog } from "@/plugins/dialog";
|
|
|
|
import { useI18n } from "vue-i18n";
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const props = defineProps<{ slug: string }>();
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const page = ref(1);
|
|
|
|
const COMMENTS_PER_PAGE = 10;
|
|
|
|
|
|
|
|
const { currentActor } = useCurrentActorClient();
|
|
|
|
|
|
|
|
const {
|
|
|
|
result: discussionResult,
|
|
|
|
onError: onDiscussionError,
|
|
|
|
subscribeToMore,
|
|
|
|
fetchMore,
|
|
|
|
loading: discussionLoading,
|
|
|
|
} = useQuery<{ discussion: IDiscussion }>(
|
|
|
|
GET_DISCUSSION,
|
|
|
|
() => ({
|
|
|
|
slug: props.slug,
|
|
|
|
page: page.value,
|
|
|
|
limit: COMMENTS_PER_PAGE,
|
|
|
|
}),
|
|
|
|
() => ({
|
|
|
|
enabled: props.slug !== undefined,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
subscribeToMore({
|
|
|
|
document: DISCUSSION_COMMENT_CHANGED,
|
|
|
|
variables: {
|
|
|
|
slug: props.slug,
|
|
|
|
page: page.value,
|
|
|
|
limit: COMMENTS_PER_PAGE,
|
2020-07-09 17:24:28 +02:00
|
|
|
},
|
2022-07-12 10:55:28 +02:00
|
|
|
updateQuery(
|
|
|
|
previousResult: any,
|
|
|
|
{ subscriptionData }: { subscriptionData: any }
|
|
|
|
) {
|
|
|
|
const previousDiscussion = previousResult.discussion;
|
|
|
|
const lastComment =
|
|
|
|
subscriptionData.data.discussionCommentChanged.lastComment;
|
|
|
|
hasMoreComments.value = !previousDiscussion.comments.elements.some(
|
|
|
|
(comment: IComment) => comment.id === lastComment.id
|
|
|
|
);
|
|
|
|
if (hasMoreComments.value) {
|
|
|
|
return {
|
|
|
|
discussion: {
|
|
|
|
...previousDiscussion,
|
|
|
|
lastComment: lastComment,
|
|
|
|
comments: {
|
|
|
|
elements: [
|
|
|
|
...previousDiscussion.comments.elements.filter(
|
|
|
|
({ id }: { id: string }) => id !== lastComment.id
|
|
|
|
),
|
|
|
|
lastComment,
|
|
|
|
],
|
|
|
|
total: previousDiscussion.comments.total + 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
return previousDiscussion;
|
|
|
|
},
|
|
|
|
});
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const discussion = computed(() => discussionResult.value?.discussion);
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-11-03 17:21:51 +01:00
|
|
|
const group = computed(() => discussion.value?.actor);
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-08-26 16:08:58 +02:00
|
|
|
const Editor = defineAsyncComponent(
|
|
|
|
() => import("@/components/TextEditor.vue")
|
|
|
|
);
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
useHead({
|
|
|
|
title: computed(() => discussion.value?.title ?? ""),
|
|
|
|
});
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const newComment = ref("");
|
|
|
|
const newTitle = ref("");
|
|
|
|
const editTitleMode = ref(false);
|
|
|
|
const hasMoreComments = ref(true);
|
|
|
|
const error = ref<string | null>(null);
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const { mutate: replyToDiscussionMutation } = useMutation(REPLY_TO_DISCUSSION);
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const reply = () => {
|
|
|
|
if (newComment.value === "") return;
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
replyToDiscussionMutation({
|
|
|
|
discussionId: discussion.value?.id,
|
|
|
|
text: newComment.value,
|
|
|
|
});
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
newComment.value = "";
|
|
|
|
};
|
2020-08-14 11:32:23 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const { mutate: updateComment } = useMutation<
|
|
|
|
{ updateComment: IComment },
|
|
|
|
{ commentId: string; text: string }
|
|
|
|
>(UPDATE_COMMENT, () => ({
|
|
|
|
update: (
|
|
|
|
store: ApolloCache<{ deleteComment: IComment }>,
|
|
|
|
{ data }: FetchResult
|
|
|
|
) => {
|
|
|
|
if (!data || !data.deleteComment) return;
|
|
|
|
const discussionData = store.readQuery<{
|
|
|
|
discussion: IDiscussion;
|
|
|
|
}>({
|
|
|
|
query: GET_DISCUSSION,
|
2020-07-09 17:24:28 +02:00
|
|
|
variables: {
|
2022-07-12 10:55:28 +02:00
|
|
|
slug: props.slug,
|
|
|
|
page: page.value,
|
2020-07-09 17:24:28 +02:00
|
|
|
},
|
|
|
|
});
|
2022-07-12 10:55:28 +02:00
|
|
|
if (!discussionData) return;
|
|
|
|
const { discussion: discussionCached } = discussionData;
|
|
|
|
const index = discussionCached.comments.elements.findIndex(
|
|
|
|
({ id }) => id === data.deleteComment.id
|
|
|
|
);
|
|
|
|
if (index > -1) {
|
|
|
|
discussionCached.comments.elements.splice(index, 1);
|
|
|
|
discussionCached.comments.total -= 1;
|
|
|
|
}
|
|
|
|
store.writeQuery({
|
|
|
|
query: GET_DISCUSSION,
|
|
|
|
variables: { slug: props.slug, page: page.value },
|
|
|
|
data: { discussion: discussionCached },
|
|
|
|
});
|
|
|
|
},
|
|
|
|
}));
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const { mutate: deleteComment } = useMutation<
|
|
|
|
{ deleteComment: { id: string } },
|
|
|
|
{ commentId: string }
|
|
|
|
>(DELETE_COMMENT, () => ({
|
|
|
|
update: (store: ApolloCache<{ deleteComment: IComment }>, { data }) => {
|
|
|
|
const id = data?.deleteComment?.id;
|
|
|
|
if (!id) return;
|
|
|
|
store.writeFragment({
|
|
|
|
id: `Comment:${id}`,
|
|
|
|
fragment: gql`
|
|
|
|
fragment CommentDeleted on Comment {
|
|
|
|
deletedAt
|
|
|
|
actor {
|
|
|
|
id
|
|
|
|
}
|
|
|
|
text
|
2020-08-14 11:32:23 +02:00
|
|
|
}
|
2022-07-12 10:55:28 +02:00
|
|
|
`,
|
|
|
|
data: {
|
|
|
|
deletedAt: new Date(),
|
|
|
|
text: "",
|
|
|
|
actor: null,
|
2020-08-14 11:32:23 +02:00
|
|
|
},
|
|
|
|
});
|
2022-07-12 10:55:28 +02:00
|
|
|
},
|
|
|
|
}));
|
2020-08-14 11:32:23 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const loadMoreComments = async (): Promise<void> => {
|
|
|
|
if (!hasMoreComments.value) return;
|
|
|
|
page.value++;
|
|
|
|
try {
|
|
|
|
await fetchMore({
|
|
|
|
// New variables
|
2020-08-14 11:32:23 +02:00
|
|
|
variables: {
|
2022-07-12 10:55:28 +02:00
|
|
|
slug: props.slug,
|
|
|
|
page: page.value,
|
|
|
|
limit: COMMENTS_PER_PAGE,
|
2020-08-14 11:32:23 +02:00
|
|
|
},
|
|
|
|
});
|
2022-07-12 10:55:28 +02:00
|
|
|
hasMoreComments.value = !discussion.value?.comments.elements
|
|
|
|
.map(({ id }) => id)
|
|
|
|
.includes(discussion.value?.lastComment?.id);
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e);
|
2020-08-14 11:32:23 +02:00
|
|
|
}
|
2022-07-12 10:55:28 +02:00
|
|
|
};
|
2020-08-14 11:32:23 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const { mutate: updateDiscussionMutation } = useMutation<{
|
|
|
|
updateDiscussion: IDiscussion;
|
|
|
|
}>(UPDATE_DISCUSSION);
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const updateDiscussion = async (): Promise<void> => {
|
|
|
|
updateDiscussionMutation({
|
|
|
|
discussionId: discussion.value?.id,
|
|
|
|
title: newTitle.value,
|
|
|
|
});
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
editTitleMode.value = false;
|
|
|
|
};
|
2021-03-04 17:39:50 +01:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const { t } = useI18n({ useScope: "global" });
|
|
|
|
const dialog = inject<Dialog>("dialog");
|
|
|
|
|
|
|
|
const openDeleteDiscussionConfirmation = (): void => {
|
|
|
|
dialog?.confirm({
|
2022-08-26 16:08:58 +02:00
|
|
|
variant: "danger",
|
2022-07-12 10:55:28 +02:00
|
|
|
title: t("Delete this discussion"),
|
|
|
|
message: t("Are you sure you want to delete this entire discussion?"),
|
|
|
|
confirmText: t("Delete discussion"),
|
|
|
|
cancelText: t("Cancel"),
|
|
|
|
onConfirm: () =>
|
|
|
|
deleteConversation({
|
|
|
|
discussionId: discussion.value?.id,
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
const { mutate: deleteConversation, onDone: deleteConversationDone } =
|
|
|
|
useMutation(DELETE_DISCUSSION);
|
|
|
|
|
|
|
|
deleteConversationDone(() => {
|
|
|
|
if (discussion.value?.actor) {
|
|
|
|
router.push({
|
|
|
|
name: RouteName.DISCUSSION_LIST,
|
|
|
|
params: {
|
|
|
|
preferredUsername: usernameWithDomain(discussion.value.actor),
|
2020-07-09 17:24:28 +02:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2022-07-12 10:55:28 +02:00
|
|
|
});
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
onDiscussionError((discussionError) =>
|
|
|
|
handleErrors(discussionError.graphQLErrors as AbsintheGraphQLError[])
|
|
|
|
);
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
const handleErrors = async (errors: AbsintheGraphQLError[]): Promise<void> => {
|
|
|
|
if (errors[0].message.includes("No such discussion")) {
|
|
|
|
await router.push({ name: RouteName.PAGE_NOT_FOUND });
|
2020-07-09 17:24:28 +02:00
|
|
|
}
|
2022-07-12 10:55:28 +02:00
|
|
|
if (errors[0].code === "unauthorized") {
|
|
|
|
error.value = errors[0].message;
|
2020-07-09 17:24:28 +02:00
|
|
|
}
|
2022-07-12 10:55:28 +02:00
|
|
|
};
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
onMounted(() => {
|
|
|
|
window.addEventListener("scroll", handleScroll);
|
|
|
|
});
|
2020-07-09 17:24:28 +02:00
|
|
|
|
2022-07-12 10:55:28 +02:00
|
|
|
onUnmounted(() => {
|
|
|
|
window.removeEventListener("scroll", handleScroll);
|
|
|
|
});
|
|
|
|
|
|
|
|
const handleScroll = (): void => {
|
|
|
|
const scrollTop =
|
|
|
|
(document.documentElement && document.documentElement.scrollTop) ||
|
|
|
|
document.body.scrollTop;
|
|
|
|
const scrollHeight =
|
|
|
|
(document.documentElement && document.documentElement.scrollHeight) ||
|
|
|
|
document.body.scrollHeight;
|
|
|
|
const clientHeight =
|
|
|
|
document.documentElement.clientHeight || window.innerHeight;
|
|
|
|
const scrolledToBottom =
|
|
|
|
Math.ceil(scrollTop + clientHeight + 800) >= scrollHeight;
|
|
|
|
if (scrolledToBottom) {
|
|
|
|
loadMoreComments();
|
2020-07-09 17:24:28 +02:00
|
|
|
}
|
2022-07-12 10:55:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const isCurrentActorAGroupModerator = computed((): boolean => {
|
|
|
|
return hasCurrentActorThisRole([
|
|
|
|
MemberRole.MODERATOR,
|
|
|
|
MemberRole.ADMINISTRATOR,
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
const { result: membershipsResult } = useQuery<{
|
|
|
|
person: Pick<IPerson, "memberships">;
|
|
|
|
}>(
|
|
|
|
PERSON_MEMBERSHIPS,
|
|
|
|
() => ({ id: currentActor.value?.id }),
|
|
|
|
() => ({ enabled: currentActor.value?.id !== undefined })
|
|
|
|
);
|
|
|
|
const memberships = computed(() => membershipsResult.value?.person.memberships);
|
|
|
|
|
|
|
|
const hasCurrentActorThisRole = (givenRole: string | string[]): boolean => {
|
|
|
|
const roles = Array.isArray(givenRole)
|
|
|
|
? givenRole
|
|
|
|
: ([givenRole] as MemberRole[]);
|
|
|
|
return (
|
|
|
|
(memberships.value?.total ?? 0) > 0 &&
|
|
|
|
roles.includes(memberships.value?.elements[0].role as MemberRole)
|
|
|
|
);
|
|
|
|
};
|
|
|
|
</script>
|