[CORL-458] open user drawer when flagger username clicked (#2436)

* open user drawer when flagger useranme clicked

* fix comment author click

* update style of flagger button

* update snapshots

* chore: use round-corners design token
This commit is contained in:
Tessa Thornton
2019-08-05 07:02:13 -04:00
committed by Vinh
parent 5df2de6afc
commit 3694794b01
17 changed files with 191 additions and 120 deletions
@@ -1,7 +1,7 @@
.root {
border: 1px solid var(--palette-success-main);
box-sizing: border-box;
border-radius: 2px;
border-radius: var(--round-corners);
width: 65px;
height: 50px;
display: flex;
@@ -17,6 +17,7 @@ import ToxicityLabel from "./ToxicityLabel";
interface Props {
comment: FlagDetailsContainer_comment;
settings: FlagDetailsContainer_settings;
onUsernameClick: (id?: string) => void;
}
const FlagDetailsContainer: FunctionComponent<Props> = ({
@@ -24,6 +25,7 @@ const FlagDetailsContainer: FunctionComponent<Props> = ({
revision: { metadata },
flags: { nodes },
},
onUsernameClick,
settings,
}) => {
const offensive = nodes.filter(
@@ -63,6 +65,9 @@ const FlagDetailsContainer: FunctionComponent<Props> = ({
{offensive.map((flag, i) => (
<FlagDetailsEntry
key={i}
onClick={() =>
flag.flagger ? onUsernameClick(flag.flagger.id) : null
}
user={flag.flagger ? flag.flagger.username : <NotAvailable />}
details={flag.additionalDetails}
/>
@@ -79,6 +84,9 @@ const FlagDetailsContainer: FunctionComponent<Props> = ({
>
{spam.map((flag, i) => (
<FlagDetailsEntry
onClick={() =>
flag.flagger ? onUsernameClick(flag.flagger.id) : null
}
key={i}
user={flag.flagger ? flag.flagger.username : <NotAvailable />}
details={flag.additionalDetails}
@@ -97,6 +105,7 @@ const enhanced = withFragmentContainer<Props>({
nodes {
flagger {
username
id
}
reason
additionalDetails
@@ -16,3 +16,22 @@
color: var(--palette-text-primary);
font-style: italic;
}
.flagger {
margin-right: var(--mini-unit);
padding: var(--spacing-1);
margin-left: calc(-1 * var(--spacing-1));
line-height: calc(16rem / var(--rem-base));
&:hover {
background-color: var(--palette-grey-lightest);
border-radius: var(--round-corners);
border-style: none;
}
&:active {
background-color: var(--palette-grey-lighter);
border-radius: var(--round-corners);
border-style: none;
}
}
@@ -1,19 +1,35 @@
import React, { FunctionComponent } from "react";
import { BaseButton } from "coral-ui/components";
import styles from "./FlagDetailsEntry.css";
interface Props {
user: React.ReactNode;
details?: React.ReactNode;
onClick?: () => void;
}
const FlagDetailsEntry: FunctionComponent<Props> = ({ user, details }) => {
const FlagDetailsEntry: FunctionComponent<Props> = ({
user,
details,
onClick,
}) => {
return (
<div>
<span className={styles.user}>
{user}
{details && ":"}
</span>
{onClick && (
<BaseButton className={styles.flagger} onClick={onClick}>
<span className={styles.user}>
{user}
{details && ":"}
</span>
</BaseButton>
)}
{!onClick && (
<span className={styles.user}>
{user}
{details && ":"}
</span>
)}
{details && <span className={styles.details}>{details}</span>}
</div>
);
@@ -42,6 +42,7 @@ it("renders all markers", () => {
},
},
},
onUsernameClick: () => null,
};
const renderer = createRenderer();
renderer.render(<MarkersContainerN {...props} />);
@@ -81,6 +82,7 @@ it("renders some markers", () => {
},
},
},
onUsernameClick: () => null,
};
const renderer = createRenderer();
renderer.render(<MarkersContainerN {...props} />);
@@ -11,6 +11,7 @@ import Markers from "./Markers";
interface MarkersContainerProps {
comment: MarkersContainer_comment;
onUsernameClick: (id?: string) => void;
settings: MarkersContainer_settings;
}
@@ -116,6 +117,7 @@ export class MarkersContainer extends React.Component<MarkersContainerProps> {
details={
doesHaveDetails ? (
<FlagDetailsContainer
onUsernameClick={this.props.onUsernameClick}
comment={this.props.comment}
settings={this.props.settings}
/>
@@ -15,13 +15,13 @@
&:hover {
background-color: var(--palette-grey-lightest);
border-radius: 2px;
border-radius: var(--round-corners);
border-style: none;
}
&:active {
background-color: var(--palette-grey-lighter);
border-radius: 2px;
border-radius: var(--round-corners);
border-style: none;
}
}
@@ -1,6 +1,6 @@
import cn from "classnames";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import React, { FunctionComponent, useCallback } from "react";
import { PropTypesOf } from "coral-framework/types";
import {
@@ -79,115 +79,127 @@ const ModerateCard: FunctionComponent<Props> = ({
moderatedBy,
mini = false,
hideUsername = false,
}) => (
<Card
className={cn(
styles.root,
{ [styles.borderless]: mini },
{ [styles.dangling]: dangling }
)}
data-testid={`moderate-comment-${id}`}
>
<Flex>
<div className={styles.mainContainer}>
<div
className={cn(styles.topBar, {
[styles.topBarMini]: mini && !inReplyTo,
})}
>
<Flex alignItems="center">
{!hideUsername && (
<BaseButton onClick={onUsernameClick} className={styles.username}>
<Username>{username}</Username>
</BaseButton>
)}
<Timestamp>{createdAt}</Timestamp>
<FeatureButton featured={featured} onClick={onFeature} />
</Flex>
{inReplyTo && (
<div>
<InReplyTo>{inReplyTo}</InReplyTo>
</div>
)}
</div>
<CommentContent
suspectWords={suspectWords}
bannedWords={bannedWords}
className={styles.content}
>
{body}
</CommentContent>
<div className={styles.footer}>
<HorizontalGutter>
<div>
<Localized id="moderate-comment-viewContext">
<TextLink
className={styles.link}
href={viewContextHref}
target="_blank"
}) => {
const commentAuthorClick = useCallback(() => {
onUsernameClick();
}, [onUsernameClick]);
return (
<Card
className={cn(
styles.root,
{ [styles.borderless]: mini },
{ [styles.dangling]: dangling }
)}
data-testid={`moderate-comment-${id}`}
>
<Flex>
<div className={styles.mainContainer}>
<div
className={cn(styles.topBar, {
[styles.topBarMini]: mini && !inReplyTo,
})}
>
<Flex alignItems="center">
{!hideUsername && (
<BaseButton
onClick={commentAuthorClick}
className={styles.username}
>
View Context
</TextLink>
</Localized>
</div>
{showStory && (
<Username>{username}</Username>
</BaseButton>
)}
<Timestamp>{createdAt}</Timestamp>
<FeatureButton featured={featured} onClick={onFeature} />
</Flex>
{inReplyTo && (
<div>
<Localized id="moderate-comment-story">
<span className={styles.story}>Story</span>
</Localized>
{": "}
<span className={styles.storyTitle}>{storyTitle}</span>{" "}
<Localized id="moderate-comment-moderateStory">
<InReplyTo>{inReplyTo}</InReplyTo>
</div>
)}
</div>
<CommentContent
suspectWords={suspectWords}
bannedWords={bannedWords}
className={styles.content}
>
{body}
</CommentContent>
<div className={styles.footer}>
<HorizontalGutter>
<div>
<Localized id="moderate-comment-viewContext">
<TextLink
className={styles.link}
href={storyHref}
onClick={onModerateStory}
href={viewContextHref}
target="_blank"
>
Moderate Story
View Context
</TextLink>
</Localized>
</div>
)}
<MarkersContainer comment={comment} settings={settings} />
</HorizontalGutter>
{showStory && (
<div>
<Localized id="moderate-comment-story">
<span className={styles.story}>Story</span>
</Localized>
{": "}
<span className={styles.storyTitle}>{storyTitle}</span>{" "}
<Localized id="moderate-comment-moderateStory">
<TextLink
className={styles.link}
href={storyHref}
onClick={onModerateStory}
>
Moderate Story
</TextLink>
</Localized>
</div>
)}
<MarkersContainer
onUsernameClick={onUsernameClick}
comment={comment}
settings={settings}
/>
</HorizontalGutter>
</div>
</div>
</div>
<div
className={cn(styles.separator, { [styles.ruledSeparator]: !mini })}
/>
<Flex
className={cn(styles.aside, {
[styles.asideWithoutReplyTo]: !inReplyTo,
[styles.asideMini]: mini && !inReplyTo,
[styles.asideMiniWithReplyTo]: mini && inReplyTo,
})}
alignItems="center"
direction="column"
itemGutter
>
{!mini && (
<Localized id="moderate-comment-decision">
<div className={styles.decision}>DECISION</div>
</Localized>
)}
<Flex itemGutter>
<RejectButton
onClick={onReject}
invert={status === "rejected"}
disabled={status === "rejected" || dangling}
className={cn({ [styles.miniButton]: mini })}
/>
<ApproveButton
onClick={onApprove}
invert={status === "approved"}
disabled={status === "approved" || dangling}
className={cn({ [styles.miniButton]: mini })}
/>
<div
className={cn(styles.separator, { [styles.ruledSeparator]: !mini })}
/>
<Flex
className={cn(styles.aside, {
[styles.asideWithoutReplyTo]: !inReplyTo,
[styles.asideMini]: mini && !inReplyTo,
[styles.asideMiniWithReplyTo]: mini && inReplyTo,
})}
alignItems="center"
direction="column"
itemGutter
>
{!mini && (
<Localized id="moderate-comment-decision">
<div className={styles.decision}>DECISION</div>
</Localized>
)}
<Flex itemGutter>
<RejectButton
onClick={onReject}
invert={status === "rejected"}
disabled={status === "rejected" || dangling}
className={cn({ [styles.miniButton]: mini })}
/>
<ApproveButton
onClick={onApprove}
invert={status === "approved"}
disabled={status === "approved" || dangling}
className={cn({ [styles.miniButton]: mini })}
/>
</Flex>
{moderatedBy}
</Flex>
{moderatedBy}
</Flex>
</Flex>
</Card>
);
</Card>
);
};
export default ModerateCard;
@@ -114,12 +114,15 @@ const ModerateCardContainer: FunctionComponent<Props> = ({
}
}, [comment]);
const onUsernameClicked = useCallback(() => {
if (!usernameClicked) {
return;
}
usernameClicked(comment.author!.id);
}, [usernameClicked, comment]);
const onUsernameClicked = useCallback(
(id?: string) => {
if (!usernameClicked) {
return;
}
usernameClicked(id || comment.author!.id);
},
[usernameClicked, comment]
);
const handleModerateStory = useCallback(
(e: React.MouseEvent) => {
@@ -1,7 +1,7 @@
.root {
border: 1px solid var(--palette-error-main);
box-sizing: border-box;
border-radius: 2px;
border-radius: var(--round-corners);
width: 65px;
height: 50px;
display: flex;
@@ -30,6 +30,7 @@ exports[`renders all markers 1`] = `
"status": "PREMOD",
}
}
onUsernameClick={[Function]}
settings={
Object {
"integrations": Object {
@@ -169,6 +170,7 @@ exports[`renders some markers 1`] = `
"status": "PREMOD",
}
}
onUsernameClick={[Function]}
settings={
Object {
"integrations": Object {
@@ -66,6 +66,7 @@ exports[`renders approved correctly 1`] = `
</div>
<Relay(MarkersContainer)
comment={Object {}}
onUsernameClick={[Function]}
settings={Object {}}
/>
</ForwardRef(forwardRef)>
@@ -175,6 +176,7 @@ exports[`renders correctly 1`] = `
</div>
<Relay(MarkersContainer)
comment={Object {}}
onUsernameClick={[Function]}
settings={Object {}}
/>
</ForwardRef(forwardRef)>
@@ -283,6 +285,7 @@ exports[`renders dangling correctly 1`] = `
</div>
<Relay(MarkersContainer)
comment={Object {}}
onUsernameClick={[Function]}
settings={Object {}}
/>
</ForwardRef(forwardRef)>
@@ -393,6 +396,7 @@ exports[`renders rejected correctly 1`] = `
</div>
<Relay(MarkersContainer)
comment={Object {}}
onUsernameClick={[Function]}
settings={Object {}}
/>
</ForwardRef(forwardRef)>
@@ -507,6 +511,7 @@ exports[`renders reply correctly 1`] = `
</div>
<Relay(MarkersContainer)
comment={Object {}}
onUsernameClick={[Function]}
settings={Object {}}
/>
</ForwardRef(forwardRef)>
@@ -644,6 +649,7 @@ exports[`renders story info 1`] = `
</div>
<Relay(MarkersContainer)
comment={Object {}}
onUsernameClick={[Function]}
settings={Object {}}
/>
</ForwardRef(forwardRef)>
@@ -9,7 +9,7 @@
border-width: 1px;
border-style: solid;
border-color: var(--palette-grey-lighter);
border-radius: 2px;
border-radius: var(--round-corners);
margin-top: var(--spacing-1);
}
@@ -115,7 +115,7 @@ hr {
border-style: solid;
border-color: var(--palette-grey-lighter);
border-width: 1px;
border-radius: 2px;
border-radius: var(--round-corners);
padding-left: var(--spacing-2);
padding-right: var(--spacing-1);
}
@@ -9,7 +9,7 @@
border-width: 1px;
border-style: solid;
border-color: var(--palette-grey-lighter);
border-radius: 2px;
border-radius: var(--round-corners);
margin-top: var(--spacing-1);
}
@@ -201,7 +201,7 @@ $fullscreenZIndex: 10;
}
.cm-comment {
background: rgba(0, 0, 0, 0.05);
border-radius: 2px;
border-radius: var(--round-corners);
}
.cm-link {
color: #7f8c8d;
@@ -12,7 +12,7 @@
cursor: pointer;
user-select: none;
border: 1px solid var(--palette-grey-dark);
border-radius: 2px;
border-radius: var(--round-corners);
color: var(--palette-grey-dark);
padding: calc(0.5 * var(--mini-unit));
line-height: 1;