mirror of
https://github.com/wassname/talk.git
synced 2026-07-29 11:28:24 +08:00
* feat: support blue color in message * feat: Show message when comment is in review * feat: handle non-visible comment status * test: add feature test for handling invisible comment status * fix: apply review * chore: better comment :-) * Update isVisible.ts
180 lines
4.5 KiB
TypeScript
180 lines
4.5 KiB
TypeScript
import { graphql } from "react-relay";
|
|
import {
|
|
ConnectionHandler,
|
|
Environment,
|
|
RecordProxy,
|
|
RecordSourceSelectorProxy,
|
|
} from "relay-runtime";
|
|
|
|
import { getMe } from "talk-framework/helpers";
|
|
import { TalkContext } from "talk-framework/lib/bootstrap";
|
|
import {
|
|
commitMutationPromiseNormalized,
|
|
createMutationContainer,
|
|
MutationInput,
|
|
MutationResponsePromise,
|
|
} from "talk-framework/lib/relay";
|
|
import { CreateCommentMutation as MutationTypes } from "talk-stream/__generated__/CreateCommentMutation.graphql";
|
|
|
|
import {
|
|
incrementStoryCommentCounts,
|
|
isRolePriviledged,
|
|
isVisible,
|
|
prependCommentEdgeToProfile,
|
|
} from "../helpers";
|
|
|
|
export type CreateCommentInput = MutationInput<MutationTypes>;
|
|
|
|
function sharedUpdater(
|
|
environment: Environment,
|
|
store: RecordSourceSelectorProxy,
|
|
input: CreateCommentInput
|
|
) {
|
|
const commentEdge = store
|
|
.getRootField("createComment")!
|
|
.getLinkedRecord("edge")!;
|
|
const status = commentEdge.getLinkedRecord("node")!.getValue("status");
|
|
|
|
// If comment is not visible, we don't need to add it.
|
|
if (!isVisible(status)) {
|
|
return;
|
|
}
|
|
|
|
incrementStoryCommentCounts(store, input.storyID);
|
|
prependCommentEdgeToProfile(environment, store, commentEdge);
|
|
addCommentToStory(store, input, commentEdge);
|
|
}
|
|
|
|
/**
|
|
* update integrates new comment into the CommentConnection.
|
|
*/
|
|
function addCommentToStory(
|
|
store: RecordSourceSelectorProxy,
|
|
input: CreateCommentInput,
|
|
commentEdge: RecordProxy
|
|
) {
|
|
// Get stream proxy.
|
|
const streamProxy = store.get(input.storyID);
|
|
const connectionKey = "Stream_comments";
|
|
const filters = { orderBy: "CREATED_AT_DESC" };
|
|
|
|
if (streamProxy) {
|
|
const con = ConnectionHandler.getConnection(
|
|
streamProxy,
|
|
connectionKey,
|
|
filters
|
|
);
|
|
if (con) {
|
|
ConnectionHandler.insertEdgeBefore(con, commentEdge);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** These are needed to be included when querying for the stream. */
|
|
// tslint:disable-next-line:no-unused-expression
|
|
graphql`
|
|
fragment CreateCommentMutation_story on Story {
|
|
moderation
|
|
}
|
|
fragment CreateCommentMutation_me on User {
|
|
role
|
|
}
|
|
`;
|
|
/** end */
|
|
|
|
const mutation = graphql`
|
|
mutation CreateCommentMutation($input: CreateCommentInput!) {
|
|
createComment(input: $input) {
|
|
edge {
|
|
cursor
|
|
node {
|
|
...StreamContainer_comment @relay(mask: false)
|
|
status
|
|
}
|
|
}
|
|
clientMutationId
|
|
}
|
|
}
|
|
`;
|
|
|
|
let clientMutationId = 0;
|
|
|
|
function commit(
|
|
environment: Environment,
|
|
input: CreateCommentInput,
|
|
{ uuidGenerator, relayEnvironment }: TalkContext
|
|
) {
|
|
const me = getMe(environment)!;
|
|
const currentDate = new Date().toISOString();
|
|
const id = uuidGenerator();
|
|
|
|
const story = relayEnvironment
|
|
.getStore()
|
|
.getSource()
|
|
.get(input.storyID);
|
|
if (!story || !story.moderation) {
|
|
throw new Error("Moderation mode of the story was not included");
|
|
}
|
|
|
|
// TODO: Generate and use schema types.
|
|
const expectPremoderation =
|
|
!isRolePriviledged(me.role) && story.moderation === "PRE";
|
|
|
|
return commitMutationPromiseNormalized<MutationTypes>(environment, {
|
|
mutation,
|
|
variables: {
|
|
input: {
|
|
storyID: input.storyID,
|
|
body: input.body,
|
|
clientMutationId: clientMutationId.toString(),
|
|
},
|
|
},
|
|
optimisticResponse: {
|
|
createComment: {
|
|
edge: {
|
|
cursor: currentDate,
|
|
node: {
|
|
id,
|
|
createdAt: currentDate,
|
|
status: "NONE",
|
|
author: {
|
|
id: me.id,
|
|
username: me.username,
|
|
},
|
|
body: input.body,
|
|
editing: {
|
|
editableUntil: new Date(Date.now() + 10000),
|
|
},
|
|
actionCounts: {
|
|
reaction: {
|
|
total: 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
clientMutationId: (clientMutationId++).toString(),
|
|
},
|
|
} as any, // TODO: (cvle) generated types should contain one for the optimistic response.
|
|
optimisticUpdater: store => {
|
|
// Skip optimistic update if comment is probably premoderated.
|
|
if (expectPremoderation) {
|
|
return;
|
|
}
|
|
sharedUpdater(environment, store, input);
|
|
store.get(id)!.setValue(true, "pending");
|
|
},
|
|
updater: store => {
|
|
sharedUpdater(environment, store, input);
|
|
},
|
|
});
|
|
}
|
|
|
|
export const withCreateCommentMutation = createMutationContainer(
|
|
"createComment",
|
|
commit
|
|
);
|
|
|
|
export type CreateCommentMutation = (
|
|
input: CreateCommentInput
|
|
) => MutationResponsePromise<MutationTypes, "createComment">;
|