forked from potsda.mn/mobilizon
Comment fixes
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
b5a5de5c0c
commit
679600f003
|
@ -60,11 +60,6 @@ export const typePolicies: TypePolicies = {
|
|||
relatedEvents: pageLimitPagination<IEvent>(),
|
||||
},
|
||||
},
|
||||
Comment: {
|
||||
fields: {
|
||||
replies: pageLimitPagination<IComment>(),
|
||||
},
|
||||
},
|
||||
RootQueryType: {
|
||||
fields: {
|
||||
relayFollowers: paginatedLimitPagination<IFollower>(),
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
<span class="icons" v-if="!comment.deletedAt">
|
||||
<button
|
||||
v-if="comment.actor.id === currentActor.id"
|
||||
@click="$emit('delete-comment', comment)"
|
||||
@click="deleteComment"
|
||||
>
|
||||
<b-icon icon="delete" size="is-small" aria-hidden="true" />
|
||||
<span class="visually-hidden">{{ $t("Delete") }}</span>
|
||||
|
@ -183,7 +183,6 @@ import { CommentModeration } from "@/types/enums";
|
|||
import { CommentModel, IComment } from "../../types/comment.model";
|
||||
import { CURRENT_ACTOR_CLIENT } from "../../graphql/actor";
|
||||
import { IPerson, usernameWithDomain } from "../../types/actor";
|
||||
import { COMMENTS_THREADS, FETCH_THREAD_REPLIES } from "../../graphql/comment";
|
||||
import { IEvent } from "../../types/event.model";
|
||||
import ReportModal from "../Report/ReportModal.vue";
|
||||
import { IReport } from "../../types/report.model";
|
||||
|
@ -257,39 +256,15 @@ export default class Comment extends Vue {
|
|||
this.$emit("create-comment", this.newComment);
|
||||
this.newComment = new CommentModel();
|
||||
this.replyTo = false;
|
||||
this.showReplies = true;
|
||||
}
|
||||
|
||||
async fetchReplies(): Promise<void> {
|
||||
const parentId = this.comment.id;
|
||||
const { data } = await this.$apollo.query<{ thread: IComment[] }>({
|
||||
query: FETCH_THREAD_REPLIES,
|
||||
variables: {
|
||||
threadId: parentId,
|
||||
},
|
||||
});
|
||||
if (!data) return;
|
||||
const { thread } = data;
|
||||
const eventData = this.$apollo.getClient().readQuery<{ event: IEvent }>({
|
||||
query: COMMENTS_THREADS,
|
||||
variables: {
|
||||
eventUUID: this.event.uuid,
|
||||
},
|
||||
});
|
||||
if (!eventData) return;
|
||||
const { event } = eventData;
|
||||
const { comments } = event;
|
||||
const parentCommentIndex = comments.findIndex(
|
||||
(oldComment: IComment) => oldComment.id === parentId
|
||||
);
|
||||
const parentComment = comments[parentCommentIndex];
|
||||
if (!parentComment) return;
|
||||
parentComment.replies = thread;
|
||||
comments[parentCommentIndex] = parentComment;
|
||||
event.comments = comments;
|
||||
this.$apollo.getClient().writeQuery({
|
||||
query: COMMENTS_THREADS,
|
||||
data: { event },
|
||||
});
|
||||
deleteComment(): void {
|
||||
this.$emit("delete-comment", this.comment);
|
||||
this.showReplies = false;
|
||||
}
|
||||
|
||||
fetchReplies(): void {
|
||||
this.showReplies = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,8 +82,7 @@ import { CommentModel, IComment } from "../../types/comment.model";
|
|||
import {
|
||||
CREATE_COMMENT_FROM_EVENT,
|
||||
DELETE_COMMENT,
|
||||
COMMENTS_THREADS,
|
||||
FETCH_THREAD_REPLIES,
|
||||
COMMENTS_THREADS_WITH_REPLIES,
|
||||
} from "../../graphql/comment";
|
||||
import { CURRENT_ACTOR_CLIENT } from "../../graphql/actor";
|
||||
import { IPerson } from "../../types/actor";
|
||||
|
@ -96,7 +95,7 @@ import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
|
|||
query: CURRENT_ACTOR_CLIENT,
|
||||
},
|
||||
comments: {
|
||||
query: COMMENTS_THREADS,
|
||||
query: COMMENTS_THREADS_WITH_REPLIES,
|
||||
variables() {
|
||||
return {
|
||||
eventUUID: this.event.uuid,
|
||||
|
@ -145,6 +144,7 @@ export default class CommentTree extends Vue {
|
|||
}
|
||||
|
||||
async createCommentForEvent(comment: IComment): Promise<void> {
|
||||
console.log("creating comment", comment);
|
||||
this.emptyCommentError = ["", "<p></p>"].includes(comment.text);
|
||||
if (this.emptyCommentError) return;
|
||||
try {
|
||||
|
@ -160,21 +160,19 @@ export default class CommentTree extends Vue {
|
|||
},
|
||||
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => {
|
||||
if (data == null) return;
|
||||
const newComment = data.createComment;
|
||||
|
||||
// comments are attached to the event, so we can pass it to replies later
|
||||
newComment.event = this.event;
|
||||
const newComment = { ...data.createComment, event: this.event };
|
||||
|
||||
// we load all existing threads
|
||||
const commentThreadsData = store.readQuery<{ event: IEvent }>({
|
||||
query: COMMENTS_THREADS,
|
||||
query: COMMENTS_THREADS_WITH_REPLIES,
|
||||
variables: {
|
||||
eventUUID: this.event.uuid,
|
||||
},
|
||||
});
|
||||
if (!commentThreadsData) return;
|
||||
const { event } = commentThreadsData;
|
||||
const { comments: oldComments } = event;
|
||||
const oldComments = [...event.comments];
|
||||
|
||||
// if it's no a root comment, we first need to find
|
||||
// existing replies and add the new reply to it
|
||||
|
@ -185,44 +183,25 @@ export default class CommentTree extends Vue {
|
|||
);
|
||||
const parentComment = oldComments[parentCommentIndex];
|
||||
|
||||
let oldReplyList: IComment[] = [];
|
||||
try {
|
||||
const threadData = store.readQuery<{ thread: IComment[] }>({
|
||||
query: FETCH_THREAD_REPLIES,
|
||||
variables: {
|
||||
threadId: parentComment.id,
|
||||
},
|
||||
});
|
||||
if (!threadData) return;
|
||||
oldReplyList = threadData.thread;
|
||||
} catch (e) {
|
||||
// This simply means there's no loaded replies yet
|
||||
} finally {
|
||||
oldReplyList.push(newComment);
|
||||
|
||||
// save the updated list of replies (with the one we've just added)
|
||||
store.writeQuery({
|
||||
query: FETCH_THREAD_REPLIES,
|
||||
data: { thread: oldReplyList },
|
||||
variables: {
|
||||
threadId: parentComment.id,
|
||||
},
|
||||
});
|
||||
|
||||
// replace the root comment with has the updated list of replies in the thread list
|
||||
parentComment.replies = oldReplyList;
|
||||
event.comments.splice(parentCommentIndex, 1, parentComment);
|
||||
}
|
||||
oldComments.splice(parentCommentIndex, 1, {
|
||||
...parentComment,
|
||||
replies: [...parentComment.replies, newComment],
|
||||
});
|
||||
} else {
|
||||
// otherwise it's simply a new thread and we add it to the list
|
||||
oldComments.push(newComment);
|
||||
}
|
||||
|
||||
// finally we save the thread list
|
||||
event.comments = oldComments;
|
||||
store.writeQuery({
|
||||
query: COMMENTS_THREADS,
|
||||
data: { event },
|
||||
query: COMMENTS_THREADS_WITH_REPLIES,
|
||||
data: {
|
||||
event: {
|
||||
...event,
|
||||
comments: oldComments,
|
||||
},
|
||||
},
|
||||
variables: {
|
||||
eventUUID: this.event.uuid,
|
||||
},
|
||||
|
@ -255,58 +234,61 @@ export default class CommentTree extends Vue {
|
|||
const deletedCommentId = data.deleteComment.id;
|
||||
|
||||
const commentsData = store.readQuery<{ event: IEvent }>({
|
||||
query: COMMENTS_THREADS,
|
||||
query: COMMENTS_THREADS_WITH_REPLIES,
|
||||
variables: {
|
||||
eventUUID: this.event.uuid,
|
||||
},
|
||||
});
|
||||
if (!commentsData) return;
|
||||
const { event } = commentsData;
|
||||
const { comments: oldComments } = event;
|
||||
let updatedComments: IComment[] = [...event.comments];
|
||||
|
||||
if (comment.originComment) {
|
||||
// we have deleted a reply to a thread
|
||||
const localData = store.readQuery<{ thread: IComment[] }>({
|
||||
query: FETCH_THREAD_REPLIES,
|
||||
variables: {
|
||||
threadId: comment.originComment.id,
|
||||
},
|
||||
});
|
||||
if (!localData) return;
|
||||
const { thread: oldReplyList } = localData;
|
||||
const replies = oldReplyList.filter(
|
||||
(reply) => reply.id !== deletedCommentId
|
||||
);
|
||||
store.writeQuery({
|
||||
query: FETCH_THREAD_REPLIES,
|
||||
variables: {
|
||||
threadId: comment.originComment.id,
|
||||
},
|
||||
data: { thread: replies },
|
||||
});
|
||||
|
||||
const { originComment } = comment;
|
||||
|
||||
const parentCommentIndex = oldComments.findIndex(
|
||||
const parentCommentIndex = updatedComments.findIndex(
|
||||
(oldComment) => oldComment.id === originComment.id
|
||||
);
|
||||
const parentComment = oldComments[parentCommentIndex];
|
||||
parentComment.replies = replies;
|
||||
parentComment.totalReplies -= 1;
|
||||
oldComments.splice(parentCommentIndex, 1, parentComment);
|
||||
event.comments = oldComments;
|
||||
const parentComment = updatedComments[parentCommentIndex];
|
||||
const updatedReplies = parentComment.replies.map((reply) => {
|
||||
if (reply.id === deletedCommentId) {
|
||||
return {
|
||||
...reply,
|
||||
deletedAt: new Date().toString(),
|
||||
};
|
||||
}
|
||||
return reply;
|
||||
});
|
||||
updatedComments.splice(parentCommentIndex, 1, {
|
||||
...parentComment,
|
||||
replies: updatedReplies,
|
||||
totalReplies: parentComment.totalReplies - 1,
|
||||
});
|
||||
console.log("updatedComments", updatedComments);
|
||||
} else {
|
||||
// we have deleted a thread itself
|
||||
event.comments = oldComments.filter(
|
||||
(reply) => reply.id !== deletedCommentId
|
||||
);
|
||||
updatedComments = updatedComments.map((reply) => {
|
||||
if (reply.id === deletedCommentId) {
|
||||
return {
|
||||
...reply,
|
||||
deletedAt: new Date().toString(),
|
||||
};
|
||||
}
|
||||
return reply;
|
||||
});
|
||||
}
|
||||
store.writeQuery({
|
||||
query: COMMENTS_THREADS,
|
||||
query: COMMENTS_THREADS_WITH_REPLIES,
|
||||
variables: {
|
||||
eventUUID: this.event.uuid,
|
||||
},
|
||||
data: { event },
|
||||
data: {
|
||||
event: {
|
||||
...event,
|
||||
comments: updatedComments,
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -38,6 +38,12 @@ export const COMMENT_RECURSIVE_FRAGMENT = gql`
|
|||
}
|
||||
replies {
|
||||
...CommentFields
|
||||
inReplyToComment {
|
||||
...CommentFields
|
||||
}
|
||||
originComment {
|
||||
...CommentFields
|
||||
}
|
||||
replies {
|
||||
...CommentFields
|
||||
}
|
||||
|
@ -68,6 +74,19 @@ export const COMMENTS_THREADS = gql`
|
|||
${COMMENT_FIELDS_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const COMMENTS_THREADS_WITH_REPLIES = gql`
|
||||
query($eventUUID: UUID!) {
|
||||
event(uuid: $eventUUID) {
|
||||
id
|
||||
uuid
|
||||
comments {
|
||||
...CommentRecursive
|
||||
}
|
||||
}
|
||||
}
|
||||
${COMMENT_RECURSIVE_FRAGMENT}
|
||||
`;
|
||||
|
||||
export const CREATE_COMMENT_FROM_EVENT = gql`
|
||||
mutation CreateCommentFromEvent(
|
||||
$eventId: ID!
|
||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
|
|||
|
||||
use Absinthe.Schema.Notation
|
||||
|
||||
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
|
||||
import Absinthe.Resolution.Helpers, only: [dataloader: 1, dataloader: 2]
|
||||
|
||||
alias Mobilizon.{Actors, Addresses, Discussions}
|
||||
alias Mobilizon.GraphQL.Resolvers.{Event, Media, Tag}
|
||||
|
@ -94,7 +94,7 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
|
|||
)
|
||||
|
||||
field(:comments, list_of(:comment), description: "The comments in reply to the event") do
|
||||
resolve(dataloader(Discussions))
|
||||
resolve(dataloader(Discussions, args: %{top_level: true}))
|
||||
end
|
||||
|
||||
# field(:tracks, list_of(:track))
|
||||
|
|
|
@ -65,7 +65,7 @@ defmodule Mobilizon.Discussions.Comment do
|
|||
belongs_to(:in_reply_to_comment, Comment, foreign_key: :in_reply_to_comment_id)
|
||||
belongs_to(:origin_comment, Comment, foreign_key: :origin_comment_id)
|
||||
belongs_to(:discussion, Discussion, type: :binary_id)
|
||||
has_many(:replies, Comment, foreign_key: :in_reply_to_comment_id)
|
||||
has_many(:replies, Comment, foreign_key: :origin_comment_id)
|
||||
many_to_many(:tags, Tag, join_through: "comments_tags", on_replace: :delete)
|
||||
has_many(:mentions, Mention)
|
||||
many_to_many(:media, Media, join_through: "comments_medias", on_replace: :delete)
|
||||
|
|
|
@ -72,7 +72,7 @@ defmodule Mobilizon.Discussions do
|
|||
Read: https://hexdocs.pm/absinthe/ecto.html#dataloader
|
||||
"""
|
||||
@spec query(atom(), map()) :: Ecto.Queryable.t()
|
||||
def query(Comment, _params) do
|
||||
def query(Comment, %{top_level: true}) do
|
||||
Comment
|
||||
|> join(:left, [c], r in Comment, on: r.origin_comment_id == c.id)
|
||||
|> where([c, _], is_nil(c.in_reply_to_comment_id))
|
||||
|
@ -83,6 +83,10 @@ defmodule Mobilizon.Discussions do
|
|||
|> select([c, r], %{c | total_replies: count(r.id)})
|
||||
end
|
||||
|
||||
def query(Comment, _) do
|
||||
order_by(Comment, [c], asc: :published_at)
|
||||
end
|
||||
|
||||
def query(queryable, _) do
|
||||
queryable
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue