diff --git a/src/core/client/framework/helpers/getMe.ts b/src/core/client/framework/helpers/getMe.ts new file mode 100644 index 000000000..a8ecbdc7a --- /dev/null +++ b/src/core/client/framework/helpers/getMe.ts @@ -0,0 +1,16 @@ +declare module "relay-runtime" { + export const ROOT_ID: string; +} + +import { Environment, ROOT_ID } from "relay-runtime"; + +export default function getMe(environment: Environment) { + const source = environment.getStore().getSource(); + const root = source.get(ROOT_ID)!; + const meKey = Object.keys(root).find(s => s.startsWith("me("))!; + if (!root[meKey]) { + return null; + } + const meID = root[meKey].__ref; + return source.get(meID)!; +} diff --git a/src/core/client/framework/helpers/index.ts b/src/core/client/framework/helpers/index.ts new file mode 100644 index 000000000..653f66d98 --- /dev/null +++ b/src/core/client/framework/helpers/index.ts @@ -0,0 +1 @@ +export { default as getMe } from "./getMe"; diff --git a/src/core/client/stream/mutations/CreateCommentMutation.ts b/src/core/client/stream/mutations/CreateCommentMutation.ts index a6ac895e4..0c25e2ce0 100644 --- a/src/core/client/stream/mutations/CreateCommentMutation.ts +++ b/src/core/client/stream/mutations/CreateCommentMutation.ts @@ -1,11 +1,14 @@ import { graphql } from "react-relay"; import { Environment } from "relay-runtime"; +import uuid from "uuid/v4"; +import { getMe } from "talk-framework/helpers"; import { commitMutationPromiseNormalized, createMutationContainer, } from "talk-framework/lib/relay"; import { Omit } from "talk-framework/types"; + import { CreateCommentMutationResponse, CreateCommentMutationVariables, @@ -19,12 +22,13 @@ export type CreateCommentInput = Omit< const mutation = graphql` mutation CreateCommentMutation($input: CreateCommentInput!) { createComment(input: $input) { - comment { - id - author { - username + commentEdge { + cursor + node { + id + ...CommentContainer + ...ReplyListContainer_comment } - body } clientMutationId } @@ -34,6 +38,8 @@ const mutation = graphql` let clientMutationId = 0; function commit(environment: Environment, input: CreateCommentInput) { + const me = getMe(environment)!; + const currentDate = new Date().toISOString(); return commitMutationPromiseNormalized< CreateCommentMutationResponse["createComment"], CreateCommentMutationVariables @@ -42,22 +48,48 @@ function commit(environment: Environment, input: CreateCommentInput) { variables: { input: { ...input, + clientMutationId: clientMutationId.toString(), + }, + }, + optimisticResponse: { + createComment: { + commentEdge: { + cursor: currentDate, + node: { + id: uuid(), + createdAt: currentDate, + author: { + id: me.id, + username: me.username, + }, + body: input.body, + replies: { + edges: [], + pageInfo: { + endCursor: null, + hasNextPage: false, + }, + }, + __typename: "Comment", + }, + }, clientMutationId: (clientMutationId++).toString(), }, }, - updater: store => { - const payload = store.getRootField("createComment"); - if (payload) { - const newRecord = payload.getLinkedRecord("comment")!; - const root = store.getRoot(); - const records = root.getLinkedRecords("comments"); - if (!records) { - throw new Error("Unexpected cache state"); - } - - root.setLinkedRecords([...records, newRecord], "comments"); - } - }, + configs: [ + { + type: "RANGE_ADD", + connectionInfo: [ + { + key: "Stream_comments", + rangeBehavior: "prepend", + filters: { orderBy: "CREATED_AT_DESC" }, + }, + ], + parentID: input.assetID, + edgeName: "commentEdge", + }, + ], }); } diff --git a/src/core/server/graph/tenant/resolvers/mutation.ts b/src/core/server/graph/tenant/resolvers/mutation.ts index 8f15117c9..002a3e3b9 100644 --- a/src/core/server/graph/tenant/resolvers/mutation.ts +++ b/src/core/server/graph/tenant/resolvers/mutation.ts @@ -1,10 +1,16 @@ import { GQLMutationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types"; const Mutation: GQLMutationTypeResolver = { - createComment: async (source, { input }, ctx) => ({ - comment: await ctx.mutators.Comment.create(input), - clientMutationId: input.clientMutationId, - }), + createComment: async (source, { input }, ctx) => { + const comment = await ctx.mutators.Comment.create(input); + return { + commentEdge: { + cursor: comment.created_at, + node: comment, + }, + clientMutationId: input.clientMutationId, + }; + }, updateSettings: async (source, { input }, ctx) => ({ settings: await ctx.mutators.Settings.update(input.settings), clientMutationId: input.clientMutationId, diff --git a/src/core/server/graph/tenant/schema/schema.graphql b/src/core/server/graph/tenant/schema/schema.graphql index d51f4be16..e0684ae65 100644 --- a/src/core/server/graph/tenant/schema/schema.graphql +++ b/src/core/server/graph/tenant/schema/schema.graphql @@ -821,9 +821,9 @@ mutation. """ type CreateCommentPayload { """ - comment is the possibly created comment. + CommentEdge is the possibly created comment edge. """ - comment: Comment + commentEdge: CommentEdge """ clientMutationId is required for Relay support.