mirror of
https://github.com/wassname/talk.git
synced 2026-08-11 11:27:10 +08:00
This reverts commit e77103d872.
This commit is contained in:
@@ -243,11 +243,7 @@ export class CommentContainer extends Component<Props, State> {
|
||||
</Localized>
|
||||
)}
|
||||
{showCaret && (
|
||||
<CaretContainer
|
||||
comment={comment}
|
||||
story={story}
|
||||
viewer={viewer}
|
||||
/>
|
||||
<CaretContainer comment={comment} story={story} />
|
||||
)}
|
||||
</Flex>
|
||||
}
|
||||
@@ -333,7 +329,6 @@ const enhanced = withSetCommentIDMutation(
|
||||
...UsernameWithPopoverContainer_viewer
|
||||
...ReactionButtonContainer_viewer
|
||||
...ReportButtonContainer_viewer
|
||||
...CaretContainer_viewer
|
||||
}
|
||||
`,
|
||||
story: graphql`
|
||||
|
||||
@@ -5,7 +5,6 @@ import { graphql } from "react-relay";
|
||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
||||
import { CaretContainer_comment } from "coral-stream/__generated__/CaretContainer_comment.graphql";
|
||||
import { CaretContainer_story } from "coral-stream/__generated__/CaretContainer_story.graphql";
|
||||
import { CaretContainer_viewer } from "coral-stream/__generated__/CaretContainer_viewer.graphql";
|
||||
import { Button, ClickOutside, Icon, Popover } from "coral-ui/components";
|
||||
|
||||
import ModerationDropdownContainer from "./ModerationDropdownContainer";
|
||||
@@ -15,7 +14,6 @@ import styles from "./CaretContainer.css";
|
||||
interface Props {
|
||||
comment: CaretContainer_comment;
|
||||
story: CaretContainer_story;
|
||||
viewer: CaretContainer_viewer | null;
|
||||
}
|
||||
|
||||
const CaretContainer: FunctionComponent<Props> = props => {
|
||||
@@ -29,14 +27,12 @@ const CaretContainer: FunctionComponent<Props> = props => {
|
||||
id={popoverID}
|
||||
placement="bottom-end"
|
||||
description="A popover menu to moderate the comment"
|
||||
body={({ toggleVisibility, scheduleUpdate }) => (
|
||||
body={({ toggleVisibility }) => (
|
||||
<ClickOutside onClickOutside={toggleVisibility}>
|
||||
<ModerationDropdownContainer
|
||||
comment={props.comment}
|
||||
story={props.story}
|
||||
viewer={props.viewer}
|
||||
onDismiss={toggleVisibility}
|
||||
scheduleUpdate={scheduleUpdate}
|
||||
/>
|
||||
</ClickOutside>
|
||||
)}
|
||||
@@ -76,11 +72,6 @@ const enhanced = withFragmentContainer<Props>({
|
||||
...ModerationDropdownContainer_story
|
||||
}
|
||||
`,
|
||||
viewer: graphql`
|
||||
fragment CaretContainer_viewer on User {
|
||||
...ModerationDropdownContainer_viewer
|
||||
}
|
||||
`,
|
||||
})(CaretContainer);
|
||||
|
||||
export default enhanced;
|
||||
|
||||
-223
@@ -1,223 +0,0 @@
|
||||
import cn from "classnames";
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React, { FunctionComponent, useCallback } from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { useMutation, withFragmentContainer } from "coral-framework/lib/relay";
|
||||
import { ModerationActionsContainer_comment } from "coral-stream/__generated__/ModerationActionsContainer_comment.graphql";
|
||||
import { ModerationActionsContainer_story } from "coral-stream/__generated__/ModerationActionsContainer_story.graphql";
|
||||
import { ModerationActionsContainer_viewer } from "coral-stream/__generated__/ModerationActionsContainer_viewer.graphql";
|
||||
import { DropdownButton, DropdownDivider, Icon } from "coral-ui/components";
|
||||
|
||||
import ApproveCommentMutation from "./ApproveCommentMutation";
|
||||
import FeatureCommentMutation from "./FeatureCommentMutation";
|
||||
import RejectCommentMutation from "./RejectCommentMutation";
|
||||
import UnfeatureCommentMutation from "./UnfeatureCommentMutation";
|
||||
|
||||
import styles from "./ModerationActionsContainer.css";
|
||||
|
||||
interface Props {
|
||||
comment: ModerationActionsContainer_comment;
|
||||
story: ModerationActionsContainer_story;
|
||||
viewer: ModerationActionsContainer_viewer | null;
|
||||
onDismiss: () => void;
|
||||
onBan: () => void;
|
||||
}
|
||||
|
||||
const ModerationActionsContainer: FunctionComponent<Props> = ({
|
||||
comment,
|
||||
story,
|
||||
viewer,
|
||||
onDismiss,
|
||||
onBan,
|
||||
}) => {
|
||||
const approve = useMutation(ApproveCommentMutation);
|
||||
const feature = useMutation(FeatureCommentMutation);
|
||||
const unfeature = useMutation(UnfeatureCommentMutation);
|
||||
const reject = useMutation(RejectCommentMutation);
|
||||
|
||||
const onApprove = useCallback(() => {
|
||||
approve({ commentID: comment.id, commentRevisionID: comment.revision.id });
|
||||
}, [approve, comment]);
|
||||
const onReject = useCallback(
|
||||
() =>
|
||||
reject({ commentID: comment.id, commentRevisionID: comment.revision.id }),
|
||||
[approve, comment]
|
||||
);
|
||||
const onFeature = useCallback(() => {
|
||||
feature({
|
||||
storyID: story.id,
|
||||
commentID: comment.id,
|
||||
commentRevisionID: comment.revision.id,
|
||||
});
|
||||
onDismiss();
|
||||
}, [feature, onDismiss, story, comment]);
|
||||
const onUnfeature = useCallback(() => {
|
||||
unfeature({
|
||||
commentID: comment.id,
|
||||
storyID: story.id,
|
||||
});
|
||||
onDismiss();
|
||||
}, [unfeature, onDismiss, story, comment]);
|
||||
const approved = comment.status === "APPROVED";
|
||||
const rejected = comment.status === "REJECTED";
|
||||
const featured = comment.tags.some(t => t.code === "FEATURED");
|
||||
const banned = comment.author!.status.ban.active;
|
||||
const showBanOption =
|
||||
viewer === null ? false : comment.author!.id !== viewer.id;
|
||||
|
||||
return (
|
||||
<>
|
||||
{featured ? (
|
||||
<Localized id="comments-moderationDropdown-unfeature">
|
||||
<DropdownButton
|
||||
icon={
|
||||
<Icon className={styles.featured} size="md">
|
||||
star
|
||||
</Icon>
|
||||
}
|
||||
className={styles.featured}
|
||||
onClick={onUnfeature}
|
||||
>
|
||||
Un-Feature
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
) : (
|
||||
<Localized id="comments-moderationDropdown-feature">
|
||||
<DropdownButton
|
||||
icon={<Icon size="md">star_border</Icon>}
|
||||
onClick={onFeature}
|
||||
>
|
||||
Feature
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
)}
|
||||
{approved ? (
|
||||
<Localized id="comments-moderationDropdown-approved">
|
||||
<DropdownButton
|
||||
icon={
|
||||
<Icon className={styles.approved} size="md">
|
||||
check
|
||||
</Icon>
|
||||
}
|
||||
className={styles.approved}
|
||||
disabled
|
||||
>
|
||||
Approved
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
) : (
|
||||
<Localized id="comments-moderationDropdown-approve">
|
||||
<DropdownButton
|
||||
icon={<Icon size="md">check</Icon>}
|
||||
onClick={onApprove}
|
||||
>
|
||||
Approve
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
)}
|
||||
{rejected ? (
|
||||
<Localized id="comments-moderationDropdown-rejected">
|
||||
<DropdownButton
|
||||
icon={
|
||||
<Icon className={styles.rejected} size="md">
|
||||
close
|
||||
</Icon>
|
||||
}
|
||||
className={styles.rejected}
|
||||
disabled
|
||||
>
|
||||
Rejected
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
) : (
|
||||
<Localized id="comments-moderationDropdown-reject">
|
||||
<DropdownButton
|
||||
icon={<Icon size="md">close</Icon>}
|
||||
onClick={onReject}
|
||||
>
|
||||
Reject
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
)}
|
||||
{showBanOption && (
|
||||
<>
|
||||
<DropdownDivider />
|
||||
{banned ? (
|
||||
<Localized id="comments-moderationDropdown-banned">
|
||||
<DropdownButton
|
||||
icon={
|
||||
<div className={cn(styles.banIcon, styles.banned)}>
|
||||
<Icon size="sm">block</Icon>
|
||||
</div>
|
||||
}
|
||||
className={styles.banned}
|
||||
disabled
|
||||
>
|
||||
Banned
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
) : (
|
||||
<Localized id="comments-moderationDropdown-ban">
|
||||
<DropdownButton
|
||||
icon={
|
||||
<div className={styles.banIcon}>
|
||||
<Icon size="sm">block</Icon>
|
||||
</div>
|
||||
}
|
||||
onClick={onBan}
|
||||
>
|
||||
Ban User
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<DropdownDivider />
|
||||
<Localized id="comments-moderationDropdown-goToModerate">
|
||||
<DropdownButton
|
||||
href={`/admin/moderate/comment/${comment.id}`}
|
||||
target="_blank"
|
||||
anchor
|
||||
>
|
||||
Go to Moderate
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const enhanced = withFragmentContainer<Props>({
|
||||
comment: graphql`
|
||||
fragment ModerationActionsContainer_comment on Comment {
|
||||
id
|
||||
author {
|
||||
id
|
||||
status {
|
||||
ban {
|
||||
active
|
||||
}
|
||||
}
|
||||
}
|
||||
revision {
|
||||
id
|
||||
}
|
||||
status
|
||||
tags {
|
||||
code
|
||||
}
|
||||
}
|
||||
`,
|
||||
story: graphql`
|
||||
fragment ModerationActionsContainer_story on Story {
|
||||
id
|
||||
}
|
||||
`,
|
||||
viewer: graphql`
|
||||
fragment ModerationActionsContainer_viewer on User {
|
||||
id
|
||||
}
|
||||
`,
|
||||
})(ModerationActionsContainer);
|
||||
|
||||
export default enhanced;
|
||||
-10
@@ -10,13 +10,3 @@
|
||||
color: var(--palette-primary-dark);
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
.banned {
|
||||
color: var(--palette-error-dark);
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
.banIcon {
|
||||
width: 18px;
|
||||
height: 14px;
|
||||
text-align: center;
|
||||
line-height: 12px;
|
||||
}
|
||||
+128
-41
@@ -1,54 +1,153 @@
|
||||
import React, { FunctionComponent, useCallback, useState } from "react";
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React, { FunctionComponent, useCallback } from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
||||
import { useMutation, withFragmentContainer } from "coral-framework/lib/relay";
|
||||
import { ModerationDropdownContainer_comment } from "coral-stream/__generated__/ModerationDropdownContainer_comment.graphql";
|
||||
import { ModerationDropdownContainer_story } from "coral-stream/__generated__/ModerationDropdownContainer_story.graphql";
|
||||
import { ModerationDropdownContainer_viewer } from "coral-stream/__generated__/ModerationDropdownContainer_viewer.graphql";
|
||||
import { Dropdown } from "coral-ui/components";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownButton,
|
||||
DropdownDivider,
|
||||
Icon,
|
||||
} from "coral-ui/components";
|
||||
|
||||
import UserBanPopoverContainer from "../UserBanPopover/UserBanPopoverContainer";
|
||||
import ModerationActionsContainer from "./ModerationActionsContainer";
|
||||
import ApproveCommentMutation from "./ApproveCommentMutation";
|
||||
import FeatureCommentMutation from "./FeatureCommentMutation";
|
||||
import RejectCommentMutation from "./RejectCommentMutation";
|
||||
import UnfeatureCommentMutation from "./UnfeatureCommentMutation";
|
||||
|
||||
type View = "MODERATE" | "BAN";
|
||||
import styles from "./ModerationDropdownContainer.css";
|
||||
|
||||
interface Props {
|
||||
comment: ModerationDropdownContainer_comment;
|
||||
story: ModerationDropdownContainer_story;
|
||||
viewer: ModerationDropdownContainer_viewer | null;
|
||||
onDismiss: () => void;
|
||||
scheduleUpdate: () => void;
|
||||
}
|
||||
|
||||
const ModerationDropdownContainer: FunctionComponent<Props> = ({
|
||||
comment,
|
||||
story,
|
||||
viewer,
|
||||
onDismiss,
|
||||
scheduleUpdate,
|
||||
}) => {
|
||||
const [view, setView] = useState<View>("MODERATE");
|
||||
const onBan = useCallback(() => {
|
||||
setView("BAN");
|
||||
scheduleUpdate();
|
||||
}, [setView, scheduleUpdate]);
|
||||
const approve = useMutation(ApproveCommentMutation);
|
||||
const feature = useMutation(FeatureCommentMutation);
|
||||
const unfeature = useMutation(UnfeatureCommentMutation);
|
||||
const reject = useMutation(RejectCommentMutation);
|
||||
|
||||
const onApprove = useCallback(() => {
|
||||
approve({ commentID: comment.id, commentRevisionID: comment.revision.id });
|
||||
}, [approve, comment]);
|
||||
const onReject = useCallback(
|
||||
() =>
|
||||
reject({ commentID: comment.id, commentRevisionID: comment.revision.id }),
|
||||
[approve, comment]
|
||||
);
|
||||
const onFeature = useCallback(() => {
|
||||
feature({
|
||||
storyID: story.id,
|
||||
commentID: comment.id,
|
||||
commentRevisionID: comment.revision.id,
|
||||
});
|
||||
onDismiss();
|
||||
}, [feature, comment]);
|
||||
const onUnfeature = useCallback(() => {
|
||||
unfeature({
|
||||
commentID: comment.id,
|
||||
storyID: story.id,
|
||||
});
|
||||
onDismiss();
|
||||
}, [unfeature, comment]);
|
||||
|
||||
const approved = comment.status === "APPROVED";
|
||||
const rejected = comment.status === "REJECTED";
|
||||
const featured = comment.tags.some(t => t.code === "FEATURED");
|
||||
|
||||
return (
|
||||
<div>
|
||||
{view === "MODERATE" ? (
|
||||
<Dropdown>
|
||||
<ModerationActionsContainer
|
||||
comment={comment}
|
||||
story={story}
|
||||
viewer={viewer}
|
||||
onDismiss={onDismiss}
|
||||
onBan={onBan}
|
||||
/>
|
||||
</Dropdown>
|
||||
<Dropdown>
|
||||
{featured ? (
|
||||
<Localized id="comments-moderationDropdown-unfeature">
|
||||
<DropdownButton
|
||||
icon={
|
||||
<Icon className={styles.featured} size="md">
|
||||
star
|
||||
</Icon>
|
||||
}
|
||||
className={styles.featured}
|
||||
onClick={onUnfeature}
|
||||
>
|
||||
Un-Feature
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
) : (
|
||||
<UserBanPopoverContainer user={comment.author!} onDismiss={onDismiss} />
|
||||
<Localized id="comments-moderationDropdown-feature">
|
||||
<DropdownButton
|
||||
icon={<Icon size="md">star_border</Icon>}
|
||||
onClick={onFeature}
|
||||
>
|
||||
Feature
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
)}
|
||||
</div>
|
||||
{approved ? (
|
||||
<Localized id="comments-moderationDropdown-approved">
|
||||
<DropdownButton
|
||||
icon={
|
||||
<Icon className={styles.approved} size="md">
|
||||
check
|
||||
</Icon>
|
||||
}
|
||||
className={styles.approved}
|
||||
disabled
|
||||
>
|
||||
Approved
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
) : (
|
||||
<Localized id="comments-moderationDropdown-approve">
|
||||
<DropdownButton
|
||||
icon={<Icon size="md">check</Icon>}
|
||||
onClick={onApprove}
|
||||
>
|
||||
Approve
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
)}
|
||||
{rejected ? (
|
||||
<Localized id="comments-moderationDropdown-rejected">
|
||||
<DropdownButton
|
||||
icon={
|
||||
<Icon className={styles.rejected} size="md">
|
||||
close
|
||||
</Icon>
|
||||
}
|
||||
className={styles.rejected}
|
||||
disabled
|
||||
>
|
||||
Rejected
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
) : (
|
||||
<Localized id="comments-moderationDropdown-reject">
|
||||
<DropdownButton
|
||||
icon={<Icon size="md">close</Icon>}
|
||||
onClick={onReject}
|
||||
>
|
||||
Reject
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
)}
|
||||
<DropdownDivider />
|
||||
<Localized id="comments-moderationDropdown-goToModerate">
|
||||
<DropdownButton
|
||||
href={`/admin/moderate/comment/${comment.id}`}
|
||||
target="_blank"
|
||||
anchor
|
||||
>
|
||||
Go to Moderate
|
||||
</DropdownButton>
|
||||
</Localized>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -56,11 +155,6 @@ const enhanced = withFragmentContainer<Props>({
|
||||
comment: graphql`
|
||||
fragment ModerationDropdownContainer_comment on Comment {
|
||||
id
|
||||
author {
|
||||
id
|
||||
username
|
||||
...UserBanPopoverContainer_user
|
||||
}
|
||||
revision {
|
||||
id
|
||||
}
|
||||
@@ -68,18 +162,11 @@ const enhanced = withFragmentContainer<Props>({
|
||||
tags {
|
||||
code
|
||||
}
|
||||
...ModerationActionsContainer_comment
|
||||
}
|
||||
`,
|
||||
story: graphql`
|
||||
fragment ModerationDropdownContainer_story on Story {
|
||||
id
|
||||
...ModerationActionsContainer_story
|
||||
}
|
||||
`,
|
||||
viewer: graphql`
|
||||
fragment ModerationDropdownContainer_viewer on User {
|
||||
...ModerationActionsContainer_viewer
|
||||
}
|
||||
`,
|
||||
})(ModerationDropdownContainer);
|
||||
|
||||
-6
@@ -180,12 +180,6 @@ function commit(
|
||||
username: viewer.username,
|
||||
createdAt: viewer.createdAt,
|
||||
ignoreable: false,
|
||||
status: {
|
||||
current: viewer.status.current,
|
||||
ban: {
|
||||
active: viewer.status.ban.active,
|
||||
},
|
||||
},
|
||||
},
|
||||
body: input.body,
|
||||
revision: {
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
import { graphql } from "react-relay";
|
||||
import { Environment } from "relay-runtime";
|
||||
|
||||
import {
|
||||
commitMutationPromiseNormalized,
|
||||
createMutation,
|
||||
lookup,
|
||||
MutationInput,
|
||||
} from "coral-framework/lib/relay";
|
||||
import { GQLUser, GQLUSER_STATUS } from "coral-framework/schema";
|
||||
import { BanUserMutation } from "coral-stream/__generated__/BanUserMutation.graphql";
|
||||
|
||||
let clientMutationId = 0;
|
||||
|
||||
const BanUserMutation = createMutation(
|
||||
"banUser",
|
||||
(environment: Environment, input: MutationInput<BanUserMutation>) => {
|
||||
return commitMutationPromiseNormalized<BanUserMutation>(environment, {
|
||||
mutation: graphql`
|
||||
mutation BanUserMutation($input: BanUserInput!) {
|
||||
banUser(input: $input) {
|
||||
user {
|
||||
id
|
||||
status {
|
||||
current
|
||||
ban {
|
||||
active
|
||||
}
|
||||
}
|
||||
}
|
||||
clientMutationId
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
...input,
|
||||
clientMutationId: clientMutationId.toString(),
|
||||
},
|
||||
},
|
||||
optimisticResponse: {
|
||||
banUser: {
|
||||
user: {
|
||||
id: input.userID,
|
||||
status: {
|
||||
current: lookup<GQLUser>(
|
||||
environment,
|
||||
input.userID
|
||||
)!.status.current.concat(GQLUSER_STATUS.BANNED),
|
||||
ban: {
|
||||
active: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
clientMutationId: (clientMutationId++).toString(),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export default BanUserMutation;
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
.root {
|
||||
width: 280px;
|
||||
max-width: 80vw;
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React, { FunctionComponent, useCallback } from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { useMutation, withFragmentContainer } from "coral-framework/lib/relay";
|
||||
import { UserBanPopoverContainer_user as UserData } from "coral-stream/__generated__/UserBanPopoverContainer_user.graphql";
|
||||
import { Box, Button, Flex, Typography } from "coral-ui/components";
|
||||
|
||||
import BanUserMutation from "./BanUserMutation";
|
||||
|
||||
import styles from "./UserBanPopoverContainer.css";
|
||||
|
||||
interface Props {
|
||||
onDismiss: () => void;
|
||||
user: UserData;
|
||||
}
|
||||
|
||||
const UserBanPopoverContainer: FunctionComponent<Props> = ({
|
||||
user,
|
||||
onDismiss,
|
||||
}) => {
|
||||
const banUser = useMutation(BanUserMutation);
|
||||
const onBan = useCallback(() => {
|
||||
banUser({ userID: user.id });
|
||||
onDismiss();
|
||||
}, [user, banUser, onDismiss]);
|
||||
return (
|
||||
<Box className={styles.root} p={3}>
|
||||
<Localized id="comments-userBanPopover-title" $username={user.username}>
|
||||
<Typography variant="heading3" mb={2}>
|
||||
Ban {user.username}?
|
||||
</Typography>
|
||||
</Localized>
|
||||
<Localized id="comments-userBanPopover-description">
|
||||
<Typography variant="detail" mb={3}>
|
||||
Once banned, this user will no longer be able to comment, use
|
||||
reactions, or report comments.
|
||||
</Typography>
|
||||
</Localized>
|
||||
<Flex justifyContent="flex-end" itemGutter="half">
|
||||
<Localized id="comments-userBanPopover-cancel">
|
||||
<Button variant="outlined" size="small" onClick={onDismiss}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Localized>
|
||||
<Localized id="comments-userBanPopover-ban">
|
||||
<Button variant="filled" size="small" onClick={onBan}>
|
||||
Ban
|
||||
</Button>
|
||||
</Localized>
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const enhanced = withFragmentContainer<Props>({
|
||||
user: graphql`
|
||||
fragment UserBanPopoverContainer_user on User {
|
||||
id
|
||||
username
|
||||
status {
|
||||
current
|
||||
ban {
|
||||
active
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
})(UserBanPopoverContainer);
|
||||
|
||||
export default enhanced;
|
||||
@@ -150,12 +150,6 @@ function commit(
|
||||
username: viewer.username,
|
||||
createdAt: viewer.createdAt,
|
||||
ignoreable: false,
|
||||
status: {
|
||||
current: viewer.status.current,
|
||||
ban: {
|
||||
active: viewer.status.ban.active,
|
||||
},
|
||||
},
|
||||
},
|
||||
revision: {
|
||||
id: uuidGenerator(),
|
||||
|
||||
@@ -1,29 +1,20 @@
|
||||
import timekeeper from "timekeeper";
|
||||
|
||||
import { pureMerge } from "coral-common/utils";
|
||||
import { GQLResolver } from "coral-framework/schema";
|
||||
import { GQLResolver, GQLUSER_STATUS } from "coral-framework/schema";
|
||||
import {
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
waitForElement,
|
||||
within,
|
||||
} from "coral-framework/testHelpers";
|
||||
import {
|
||||
createComment,
|
||||
createStory,
|
||||
createUser,
|
||||
createUserStatus,
|
||||
} from "coral-stream/test/helpers/fixture";
|
||||
|
||||
import { settings } from "../../fixtures";
|
||||
import { comments, settings, stories } from "../../fixtures";
|
||||
import create from "./create";
|
||||
|
||||
const bannedUser = createUser();
|
||||
bannedUser.status = createUserStatus(true);
|
||||
|
||||
const story = createStory();
|
||||
const story = stories[0];
|
||||
const firstComment = story.comments.edges[0].node;
|
||||
const reactedComment = createComment();
|
||||
const viewer = firstComment.author!;
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
@@ -34,17 +25,22 @@ async function createTestRenderer(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => bannedUser,
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
status: {
|
||||
current: [GQLUSER_STATUS.BANNED],
|
||||
},
|
||||
}),
|
||||
story: () =>
|
||||
pureMerge<typeof story>(story, {
|
||||
comments: {
|
||||
edges: [
|
||||
...story.comments.edges,
|
||||
{
|
||||
node: pureMerge<typeof reactedComment>(reactedComment, {
|
||||
node: pureMerge<typeof comments[2]>(comments[2], {
|
||||
actionCounts: { reaction: { total: 1 } },
|
||||
}),
|
||||
cursor: reactedComment.createdAt,
|
||||
cursor: comments[2].createdAt,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -90,15 +90,6 @@ export const baseUser = createFixture<GQLUser>({
|
||||
createdAt: "2018-02-06T18:24:00.000Z",
|
||||
status: {
|
||||
current: [GQLUSER_STATUS.ACTIVE],
|
||||
ban: {
|
||||
active: false,
|
||||
history: [],
|
||||
},
|
||||
suspension: {
|
||||
active: false,
|
||||
until: null,
|
||||
history: [],
|
||||
},
|
||||
},
|
||||
ignoredUsers: [],
|
||||
comments: {
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
import {
|
||||
GQLComment,
|
||||
GQLCOMMENT_STATUS,
|
||||
GQLMODERATION_MODE,
|
||||
GQLStory,
|
||||
GQLUser,
|
||||
GQLUSER_ROLE,
|
||||
GQLUSER_STATUS,
|
||||
} from "coral-framework/schema";
|
||||
import {
|
||||
createFixture,
|
||||
denormalizeComment,
|
||||
denormalizeStory,
|
||||
} from "coral-framework/testHelpers";
|
||||
import uuid from "uuid/v4";
|
||||
|
||||
export function createDateInRange(start: Date, end: Date) {
|
||||
return new Date(
|
||||
start.getTime() + Math.random() * (end.getTime() - start.getTime())
|
||||
);
|
||||
}
|
||||
|
||||
export function randomDate() {
|
||||
return createDateInRange(new Date(2000, 0, 1), new Date());
|
||||
}
|
||||
|
||||
export function createUserStatus(banned: boolean = false) {
|
||||
return {
|
||||
current: [banned ? GQLUSER_STATUS.BANNED : GQLUSER_STATUS.ACTIVE],
|
||||
ban: {
|
||||
active: banned,
|
||||
history: [],
|
||||
},
|
||||
suspension: {
|
||||
active: false,
|
||||
until: null,
|
||||
history: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function createUser() {
|
||||
return createFixture<GQLUser>({
|
||||
id: uuid(),
|
||||
username: uuid(),
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
createdAt: randomDate().toISOString(),
|
||||
status: createUserStatus(),
|
||||
ignoredUsers: [],
|
||||
comments: {
|
||||
edges: [],
|
||||
pageInfo: {
|
||||
hasNextPage: false,
|
||||
},
|
||||
},
|
||||
ignoreable: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function createComment() {
|
||||
const revision = uuid();
|
||||
const createdAt = randomDate();
|
||||
const editableUntil = new Date(createdAt.getTime() + 30 * 60000);
|
||||
const author = createUser();
|
||||
author.createdAt = new Date(createdAt.getTime() - 60 * 60000).toISOString();
|
||||
|
||||
return denormalizeComment(
|
||||
createFixture<GQLComment>({
|
||||
id: uuid(),
|
||||
author,
|
||||
body: uuid(),
|
||||
revision: {
|
||||
id: revision,
|
||||
},
|
||||
status: GQLCOMMENT_STATUS.NONE,
|
||||
createdAt: createdAt.toISOString(),
|
||||
replies: { edges: [], pageInfo: { endCursor: null, hasNextPage: false } },
|
||||
replyCount: 0,
|
||||
editing: {
|
||||
edited: false,
|
||||
editableUntil: editableUntil.toISOString(),
|
||||
},
|
||||
actionCounts: {
|
||||
reaction: {
|
||||
total: 0,
|
||||
},
|
||||
},
|
||||
tags: [],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function createStory(createComments: boolean = true) {
|
||||
const id = uuid();
|
||||
const comments = [createComment(), createComment()];
|
||||
|
||||
return denormalizeStory(
|
||||
createFixture<GQLStory>({
|
||||
id,
|
||||
url: `http://localhost/stories/story-${id}`,
|
||||
comments: {
|
||||
edges: [
|
||||
{ node: comments[0], cursor: comments[0].createdAt },
|
||||
{ node: comments[1], cursor: comments[1].createdAt },
|
||||
],
|
||||
pageInfo: {
|
||||
hasNextPage: false,
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
title: uuid(),
|
||||
},
|
||||
isClosed: false,
|
||||
commentCounts: {
|
||||
totalVisible: 0,
|
||||
tags: {
|
||||
FEATURED: 0,
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
moderation: GQLMODERATION_MODE.POST,
|
||||
premodLinksEnable: false,
|
||||
messageBox: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -119,13 +119,6 @@ comments-userIgnorePopover-description =
|
||||
comments-userIgnorePopover-ignore = Ignore
|
||||
comments-userIgnorePopover-cancel = Cancel
|
||||
|
||||
comments-userBanPopover-title = Ban {$username}?
|
||||
comments-userBanPopover-description =
|
||||
Once banned, this user will no longer be able
|
||||
to comment, use reactions, or report comments.
|
||||
comments-userBanPopover-cancel = Cancel
|
||||
comments-userBanPopover-ban = Ban
|
||||
|
||||
comments-moderationDropdown-popover =
|
||||
.description = A popover menu to moderate the comment
|
||||
comments-moderationDropdown-feature = Feature
|
||||
@@ -134,8 +127,6 @@ comments-moderationDropdown-approve = Approve
|
||||
comments-moderationDropdown-approved = Approved
|
||||
comments-moderationDropdown-reject = Reject
|
||||
comments-moderationDropdown-rejected = Rejected
|
||||
comments-moderationDropdown-ban = Ban User
|
||||
comments-moderationDropdown-banned = Banned
|
||||
comments-moderationDropdown-goToModerate = Go to Moderate
|
||||
comments-moderationDropdown-caretButton =
|
||||
.aria-label = Moderate
|
||||
|
||||
Reference in New Issue
Block a user