From f8234e53edba529b64a90686863a2f541f316818 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 13 Jul 2020 22:23:54 +0000 Subject: [PATCH] fix: added Other as flagging reason to ui (#3014) --- .../components/ModerateCard/FlagDetails.tsx | 48 ++++++ .../ModerateCard/FlagDetailsCategory.css | 4 +- .../ModerateCard/FlagDetailsContainer.css | 3 + .../ModerateCard/FlagDetailsContainer.tsx | 162 ++++++++++-------- .../ModerateCard/FlagDetailsEntry.css | 1 + .../ModerateCard/FlagDetailsEntry.tsx | 12 +- .../admin/components/ModerateCard/Markers.css | 5 - .../admin/components/ModerateCard/Markers.tsx | 17 +- .../ModerateCard/MarkersContainer.spec.tsx | 34 ++-- .../ModerateCard/MarkersContainer.tsx | 32 +++- .../ModerateCardDetailsContainer.tsx | 15 +- .../MarkersContainer.spec.tsx.snap | 2 + src/core/client/admin/test/fixtures.ts | 17 +- src/locales/en-US/admin.ftl | 2 + 14 files changed, 209 insertions(+), 145 deletions(-) create mode 100644 src/core/client/admin/components/ModerateCard/FlagDetails.tsx create mode 100644 src/core/client/admin/components/ModerateCard/FlagDetailsContainer.css diff --git a/src/core/client/admin/components/ModerateCard/FlagDetails.tsx b/src/core/client/admin/components/ModerateCard/FlagDetails.tsx new file mode 100644 index 000000000..39d17bea8 --- /dev/null +++ b/src/core/client/admin/components/ModerateCard/FlagDetails.tsx @@ -0,0 +1,48 @@ +import React, { FunctionComponent } from "react"; + +import NotAvailable from "coral-admin/components/NotAvailable"; + +import FlagDetailsCategory from "./FlagDetailsCategory"; +import FlagDetailsEntry from "./FlagDetailsEntry"; + +interface Props { + category: React.ReactNode; + nodes: ReadonlyArray<{ + flagger: { id: string; username: string | null } | null; + additionalDetails: string | null; + }>; + onUsernameClick: (id?: string) => void; +} + +const FlagDetails: FunctionComponent = ({ + category, + nodes, + onUsernameClick, +}) => { + if (nodes.length === 0) { + return null; + } + + return ( + + {nodes.map((flag, i) => ( + + flag.flagger ? onUsernameClick(flag.flagger.id) : null + } + user={ + flag.flagger && flag.flagger.username ? ( + flag.flagger.username + ) : ( + + ) + } + details={flag.additionalDetails} + /> + ))} + + ); +}; + +export default FlagDetails; diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.css b/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.css index 5c1da6e09..2a56a7375 100644 --- a/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.css +++ b/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.css @@ -1,8 +1,8 @@ $moderateCardFlagsCategoryColor: var(--v2-colors-mono-500); .category { - font-size: var(--v2-font-size-4); - font-weight: var(--v2-font-weight-primary-regular); + font-size: var(--v2-font-size-3); + font-weight: var(--v2-font-weight-primary-bold); font-family: var(--v2-font-family-primary); line-height: var(--v2-line-height-body-short); color: $moderateCardFlagsCategoryColor; diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.css b/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.css new file mode 100644 index 000000000..e39d1fa3b --- /dev/null +++ b/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.css @@ -0,0 +1,3 @@ +.detailsDivider { + border-top: 1px solid var(--v2-colors-grey-100); +} diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.tsx b/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.tsx index 1207f6bc1..4ed57454f 100644 --- a/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.tsx +++ b/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.tsx @@ -1,20 +1,61 @@ import { Localized } from "@fluent/react/compat"; -import React, { FunctionComponent } from "react"; +import React, { FunctionComponent, useMemo } from "react"; import { graphql } from "react-relay"; -import NotAvailable from "coral-admin/components/NotAvailable"; import { TOXICITY_THRESHOLD_DEFAULT } from "coral-common/constants"; import { withFragmentContainer } from "coral-framework/lib/relay"; import { GQLCOMMENT_FLAG_REASON } from "coral-framework/schema"; import { HorizontalGutter } from "coral-ui/components/v2"; -import { FlagDetailsContainer_comment } from "coral-admin/__generated__/FlagDetailsContainer_comment.graphql"; +import { + COMMENT_FLAG_REASON, + FlagDetailsContainer_comment, +} from "coral-admin/__generated__/FlagDetailsContainer_comment.graphql"; import { FlagDetailsContainer_settings } from "coral-admin/__generated__/FlagDetailsContainer_settings.graphql"; +import FlagDetails from "./FlagDetails"; import FlagDetailsCategory from "./FlagDetailsCategory"; -import FlagDetailsEntry from "./FlagDetailsEntry"; import ToxicityLabel from "./ToxicityLabel"; +import styles from "./FlagDetailsContainer.css"; + +interface Reasons { + offensive: T[]; + abusive: T[]; + spam: T[]; + other: T[]; +} + +function reduceReasons< + T extends { readonly reason: COMMENT_FLAG_REASON | null } +>(nodes: ReadonlyArray) { + const initialValue: Reasons = { + offensive: [], + abusive: [], + spam: [], + other: [], + }; + + return nodes.reduce((reasons, node) => { + switch (node.reason) { + case GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_OFFENSIVE: + reasons.offensive.push(node); + break; + case GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_ABUSIVE: + reasons.abusive.push(node); + break; + case GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_SPAM: + reasons.spam.push(node); + break; + case GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_OTHER: + reasons.other.push(node); + break; + } + + return reasons; + }, initialValue); +} + interface Props { comment: FlagDetailsContainer_comment; settings: FlagDetailsContainer_settings; @@ -26,21 +67,16 @@ const FlagDetailsContainer: FunctionComponent = ({ onUsernameClick, settings, }) => { - const metadata = comment.revision ? comment.revision.metadata : null; - const nodes = comment.flags.nodes; + const { offensive, abusive, spam, other } = useMemo( + () => reduceReasons(comment.flags.nodes), + [comment.flags.nodes] + ); - const offensive = nodes.filter( - ({ reason }) => reason === GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_OFFENSIVE - ); - const abusive = nodes.filter( - ({ reason }) => reason === GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_ABUSIVE - ); - const spam = nodes.filter( - ({ reason }) => reason === GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_SPAM - ); + const metadata = comment.revision ? comment.revision.metadata : null; return ( +
{metadata && metadata.perspective && ( = ({ /> )} - {offensive.length > 0 && ( - - Offensive - - } - > - {offensive.map((flag, i) => ( - - flag.flagger ? onUsernameClick(flag.flagger.id) : null - } - user={flag.flagger ? flag.flagger.username : } - details={flag.additionalDetails} - /> - ))} - - )} - {abusive.length > 0 && ( - - Abusive - - } - > - {abusive.map((flag, i) => ( - - flag.flagger ? onUsernameClick(flag.flagger.id) : null - } - user={flag.flagger ? flag.flagger.username : } - details={flag.additionalDetails} - /> - ))} - - )} - {spam.length > 0 && ( - - Spam - - } - > - {spam.map((flag, i) => ( - - flag.flagger ? onUsernameClick(flag.flagger.id) : null - } - key={i} - user={flag.flagger ? flag.flagger.username : } - details={flag.additionalDetails} - /> - ))} - - )} + + Offensive + + } + nodes={offensive} + onUsernameClick={onUsernameClick} + /> + + Abusive + + } + nodes={abusive} + onUsernameClick={onUsernameClick} + /> + + Spam + + } + nodes={spam} + onUsernameClick={onUsernameClick} + /> + + Other + + } + nodes={other} + onUsernameClick={onUsernameClick} + />
); }; diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.css b/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.css index f72e899bc..19860f94b 100644 --- a/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.css +++ b/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.css @@ -12,6 +12,7 @@ $moderateCardReasonTextColor: var(--v2-colors-mono-500); .details { color: $moderateCardReasonTextColor; + display: block; font-size: var(--v2-font-size-2); font-weight: var(--v2-font-weight-primary-regular); font-family: var(--v2-font-family-primary); diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.tsx b/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.tsx index 0063feee8..4732a1d44 100644 --- a/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.tsx +++ b/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.tsx @@ -19,18 +19,10 @@ const FlagDetailsEntry: FunctionComponent = ({
{onClick && ( - - {user} - {details && ":"} - + {user} )} - {!onClick && ( - - {user} - {details && ":"} - - )} + {!onClick && {user}} {details && {details}}
); diff --git a/src/core/client/admin/components/ModerateCard/Markers.css b/src/core/client/admin/components/ModerateCard/Markers.css index 90c66826c..906915db4 100644 --- a/src/core/client/admin/components/ModerateCard/Markers.css +++ b/src/core/client/admin/components/ModerateCard/Markers.css @@ -1,5 +1,4 @@ $moderateCardDetailsHeaderColor: var(--v2-colors-mono-500); -$moderateCardDetailsDividerColor: var(--v2-colors-grey-100); .detailsButton { font-size: var(--v2-font-size-1); @@ -21,7 +20,3 @@ $moderateCardDetailsDividerColor: var(--v2-colors-grey-100); .detailsText { margin: 0; } - -.detailsDivider { - border-color: $moderateCardDetailsDividerColor; -} diff --git a/src/core/client/admin/components/ModerateCard/Markers.tsx b/src/core/client/admin/components/ModerateCard/Markers.tsx index e9b207bd0..3f797ff0e 100644 --- a/src/core/client/admin/components/ModerateCard/Markers.tsx +++ b/src/core/client/admin/components/ModerateCard/Markers.tsx @@ -1,7 +1,7 @@ import { Localized } from "@fluent/react/compat"; -import React, { FunctionComponent, useCallback, useState } from "react"; +import React, { FunctionComponent } from "react"; -import { useUUID } from "coral-framework/hooks"; +import { useToggleState, useUUID } from "coral-framework/hooks"; import { Button, ButtonIcon, @@ -18,10 +18,8 @@ interface Props { const Markers: FunctionComponent = ({ children, details }) => { const uuid = useUUID(); - const [showDetails, setShowDetails] = useState(false); - const toggleDetails = useCallback(() => setShowDetails(!showDetails), [ - showDetails, - ]); + const [showDetails, , toggleDetails] = useToggleState(); + return ( @@ -43,12 +41,7 @@ const Markers: FunctionComponent = ({ children, details }) => { )} - {showDetails && ( -
-
- {details} -
- )} + {showDetails &&
{details}
}
); }; diff --git a/src/core/client/admin/components/ModerateCard/MarkersContainer.spec.tsx b/src/core/client/admin/components/ModerateCard/MarkersContainer.spec.tsx index f8baead52..cc6f3a146 100644 --- a/src/core/client/admin/components/ModerateCard/MarkersContainer.spec.tsx +++ b/src/core/client/admin/components/ModerateCard/MarkersContainer.spec.tsx @@ -17,17 +17,18 @@ it("renders all markers", () => { actionCounts: { flag: { reasons: { - COMMENT_DETECTED_TOXIC: 1, - COMMENT_DETECTED_SPAM: 1, - COMMENT_DETECTED_RECENT_HISTORY: 1, - COMMENT_DETECTED_LINKS: 1, - COMMENT_DETECTED_BANNED_WORD: 1, - COMMENT_DETECTED_SUSPECT_WORD: 1, + COMMENT_REPORTED_SPAM: 3, + COMMENT_REPORTED_OTHER: 0, COMMENT_REPORTED_OFFENSIVE: 2, COMMENT_REPORTED_ABUSIVE: 0, - COMMENT_REPORTED_SPAM: 3, - COMMENT_DETECTED_NEW_COMMENTER: 0, + COMMENT_DETECTED_TOXIC: 1, + COMMENT_DETECTED_SUSPECT_WORD: 1, + COMMENT_DETECTED_SPAM: 1, COMMENT_DETECTED_REPEAT_POST: 1, + COMMENT_DETECTED_RECENT_HISTORY: 1, + COMMENT_DETECTED_NEW_COMMENTER: 0, + COMMENT_DETECTED_LINKS: 1, + COMMENT_DETECTED_BANNED_WORD: 1, }, }, }, @@ -55,17 +56,18 @@ it("renders some markers", () => { actionCounts: { flag: { reasons: { - COMMENT_DETECTED_TOXIC: 1, - COMMENT_DETECTED_SPAM: 0, - COMMENT_DETECTED_RECENT_HISTORY: 1, - COMMENT_DETECTED_LINKS: 0, - COMMENT_DETECTED_BANNED_WORD: 1, - COMMENT_DETECTED_SUSPECT_WORD: 0, + COMMENT_REPORTED_SPAM: 0, + COMMENT_REPORTED_OTHER: 0, COMMENT_REPORTED_OFFENSIVE: 2, COMMENT_REPORTED_ABUSIVE: 0, - COMMENT_REPORTED_SPAM: 0, - COMMENT_DETECTED_NEW_COMMENTER: 0, + COMMENT_DETECTED_TOXIC: 1, + COMMENT_DETECTED_SUSPECT_WORD: 0, + COMMENT_DETECTED_SPAM: 0, COMMENT_DETECTED_REPEAT_POST: 0, + COMMENT_DETECTED_RECENT_HISTORY: 1, + COMMENT_DETECTED_NEW_COMMENTER: 0, + COMMENT_DETECTED_LINKS: 0, + COMMENT_DETECTED_BANNED_WORD: 1, }, }, }, diff --git a/src/core/client/admin/components/ModerateCard/MarkersContainer.tsx b/src/core/client/admin/components/ModerateCard/MarkersContainer.tsx index 34dc97281..7d1ab0080 100644 --- a/src/core/client/admin/components/ModerateCard/MarkersContainer.tsx +++ b/src/core/client/admin/components/ModerateCard/MarkersContainer.tsx @@ -123,6 +123,19 @@ const markers: Array<( )) || null, + (c) => + (c.revision && + c.revision.actionCounts.flag.reasons.COMMENT_REPORTED_OTHER && ( + + + Other + {" "} + + {c.revision.actionCounts.flag.reasons.COMMENT_REPORTED_OTHER} + + + )) || + null, (c) => (c.revision && c.revision.actionCounts.flag.reasons.COMMENT_DETECTED_NEW_COMMENTER && ( @@ -138,7 +151,7 @@ export const MarkersContainer: React.FunctionComponent = ) => { const elements = useMemo( () => markers.map((cb) => cb(props.comment)).filter((m) => m), - [markers, props.comment] + [props.comment] ); return ( @@ -165,17 +178,18 @@ const enhanced = withFragmentContainer({ actionCounts { flag { reasons { - COMMENT_DETECTED_TOXIC - COMMENT_DETECTED_SPAM - COMMENT_DETECTED_RECENT_HISTORY - COMMENT_DETECTED_LINKS - COMMENT_DETECTED_BANNED_WORD - COMMENT_DETECTED_SUSPECT_WORD + COMMENT_REPORTED_SPAM + COMMENT_REPORTED_OTHER COMMENT_REPORTED_OFFENSIVE COMMENT_REPORTED_ABUSIVE - COMMENT_REPORTED_SPAM - COMMENT_DETECTED_NEW_COMMENTER + COMMENT_DETECTED_TOXIC + COMMENT_DETECTED_SUSPECT_WORD + COMMENT_DETECTED_SPAM COMMENT_DETECTED_REPEAT_POST + COMMENT_DETECTED_RECENT_HISTORY + COMMENT_DETECTED_NEW_COMMENTER + COMMENT_DETECTED_LINKS + COMMENT_DETECTED_BANNED_WORD } } } diff --git a/src/core/client/admin/components/ModerateCard/ModerateCardDetailsContainer.tsx b/src/core/client/admin/components/ModerateCard/ModerateCardDetailsContainer.tsx index fff5b506a..64ea08145 100644 --- a/src/core/client/admin/components/ModerateCard/ModerateCardDetailsContainer.tsx +++ b/src/core/client/admin/components/ModerateCard/ModerateCardDetailsContainer.tsx @@ -37,6 +37,7 @@ function hasFlagDetails(c: ModerateCardDetailsContainer_comment) { return c.revision ? c.revision.actionCounts.flag.reasons.COMMENT_REPORTED_OFFENSIVE + c.revision.actionCounts.flag.reasons.COMMENT_REPORTED_ABUSIVE + + c.revision.actionCounts.flag.reasons.COMMENT_REPORTED_OTHER + c.revision.actionCounts.flag.reasons.COMMENT_REPORTED_SPAM > 0 || c.revision.metadata.perspective : false; @@ -82,14 +83,11 @@ const ModerateCardDetailsContainer: FunctionComponent = ({ <> {doesHaveFlagDetails && ( - <> -
- - + )} )} @@ -113,6 +111,7 @@ const enhanced = withFragmentContainer({ COMMENT_REPORTED_OFFENSIVE COMMENT_REPORTED_ABUSIVE COMMENT_REPORTED_SPAM + COMMENT_REPORTED_OTHER } } } diff --git a/src/core/client/admin/components/ModerateCard/__snapshots__/MarkersContainer.spec.tsx.snap b/src/core/client/admin/components/ModerateCard/__snapshots__/MarkersContainer.spec.tsx.snap index da7dca728..0a40f90b3 100644 --- a/src/core/client/admin/components/ModerateCard/__snapshots__/MarkersContainer.spec.tsx.snap +++ b/src/core/client/admin/components/ModerateCard/__snapshots__/MarkersContainer.spec.tsx.snap @@ -20,6 +20,7 @@ exports[`renders all markers 1`] = ` "COMMENT_DETECTED_TOXIC": 1, "COMMENT_REPORTED_ABUSIVE": 0, "COMMENT_REPORTED_OFFENSIVE": 2, + "COMMENT_REPORTED_OTHER": 0, "COMMENT_REPORTED_SPAM": 3, }, }, @@ -166,6 +167,7 @@ exports[`renders some markers 1`] = ` "COMMENT_DETECTED_TOXIC": 1, "COMMENT_REPORTED_ABUSIVE": 0, "COMMENT_REPORTED_OFFENSIVE": 2, + "COMMENT_REPORTED_OTHER": 0, "COMMENT_REPORTED_SPAM": 0, }, }, diff --git a/src/core/client/admin/test/fixtures.ts b/src/core/client/admin/test/fixtures.ts index 744a682e5..ee3c18d97 100644 --- a/src/core/client/admin/test/fixtures.ts +++ b/src/core/client/admin/test/fixtures.ts @@ -643,17 +643,18 @@ export const baseComment = createFixture({ actionCounts: { flag: { reasons: { - COMMENT_DETECTED_TOXIC: 0, - COMMENT_DETECTED_SPAM: 0, - COMMENT_DETECTED_RECENT_HISTORY: 0, - COMMENT_DETECTED_LINKS: 0, - COMMENT_DETECTED_BANNED_WORD: 0, - COMMENT_DETECTED_SUSPECT_WORD: 0, + COMMENT_REPORTED_SPAM: 0, + COMMENT_REPORTED_OTHER: 0, COMMENT_REPORTED_OFFENSIVE: 0, COMMENT_REPORTED_ABUSIVE: 0, - COMMENT_REPORTED_SPAM: 0, - COMMENT_DETECTED_NEW_COMMENTER: 0, + COMMENT_DETECTED_TOXIC: 0, + COMMENT_DETECTED_SUSPECT_WORD: 0, + COMMENT_DETECTED_SPAM: 0, COMMENT_DETECTED_REPEAT_POST: 0, + COMMENT_DETECTED_RECENT_HISTORY: 0, + COMMENT_DETECTED_NEW_COMMENTER: 0, + COMMENT_DETECTED_LINKS: 0, + COMMENT_DETECTED_BANNED_WORD: 0, }, }, }, diff --git a/src/locales/en-US/admin.ftl b/src/locales/en-US/admin.ftl index 6d353aabd..c3d10208d 100644 --- a/src/locales/en-US/admin.ftl +++ b/src/locales/en-US/admin.ftl @@ -829,11 +829,13 @@ moderate-marker-offensive = Offensive moderate-marker-abusive = Abusive moderate-marker-newCommenter = New commenter moderate-marker-repeatPost = Repeat comment +moderate-marker-other = Other moderate-markers-details = Details moderate-flagDetails-offensive = Offensive moderate-flagDetails-abusive = Abusive moderate-flagDetails-spam = Spam +moderate-flagDetails-other = Other moderate-flagDetails-toxicityScore = Toxicity Score moderate-toxicityLabel-likely = Likely