Skip to content

Commit

Permalink
Merge pull request #4571 from coralproject/feat/CORL-3012-new-comment…
Browse files Browse the repository at this point in the history
…er-badge

[CORL-3012]: New commenter badge
  • Loading branch information
tessalt authored Mar 15, 2024
2 parents 1135f32 + d4e8cc2 commit 52e96d7
Show file tree
Hide file tree
Showing 20 changed files with 267 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { useDateTimeFormatter } from "coral-framework/hooks";
import { withFragmentContainer } from "coral-framework/lib/relay";
import { GQLFEATURE_FLAG } from "coral-framework/schema";
import {
ButtonSvgIcon,
CalendarIcon,
EmailActionUnreadIcon,
MultipleNeutralIcon,
PlantIcon,
RemoveIcon,
SingleNeutralProfilePictureIcon,
SvgIcon,
Expand Down Expand Up @@ -127,6 +129,28 @@ const UserHistoryDrawerContainer: FunctionComponent<Props> = ({
/>
</Flex>
)}
{settings.newCommenter?.enabled && user.newCommenter && (
<span>
<Tooltip
id="newCommenter-tooltip"
title=""
body={
<Localized id="moderate-user-drawer-newCommenter">
<span>New commenter</span>
</Localized>
}
button={({ toggleVisibility, ref }) => (
<Button
onClick={toggleVisibility}
ref={ref}
variant="text"
>
<ButtonSvgIcon Icon={PlantIcon} filled="currentColor" />
</Button>
)}
/>
</span>
)}
<div>
<UserBadgesContainer user={user} />
</div>
Expand Down Expand Up @@ -240,6 +264,7 @@ const enhanced = withFragmentContainer<Props>({
username
email
createdAt
newCommenter
}
`,
settings: graphql`
Expand All @@ -251,6 +276,9 @@ const enhanced = withFragmentContainer<Props>({
}
externalProfileURL
featureFlags
newCommenter {
enabled
}
}
`,
viewer: graphql`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import InPageNotificationsConfig from "./InPageNotificationsConfig";
import LocaleConfig from "./LocaleConfig";
import MediaLinksConfig from "./MediaLinksConfig";
import MemberBioConfig from "./MemberBioConfig";
import NewCommenterConfig from "./NewCommenterConfig";
import ReactionConfigContainer from "./ReactionConfigContainer";
import RTEConfig from "./RTEConfig";
import SitewideCommentingConfig from "./SitewideCommentingConfig";
Expand Down Expand Up @@ -64,6 +65,7 @@ const GeneralConfigContainer: React.FunctionComponent<Props> = ({
<ReactionConfigContainer disabled={submitting} settings={settings} />
<FeaturedByConfig disabled={submitting} />
<BadgeConfig disabled={submitting} />
<NewCommenterConfig disabled={submitting} />
<TopCommenterConfig disabled={submitting} />
<FlairBadgeConfigContainer disabled={submitting} settings={settings} />
<MemberBioConfig disabled={submitting} />
Expand All @@ -90,6 +92,7 @@ const enhanced = withFragmentContainer<Props>({
...FeaturedByConfig_formValues @relay(mask: false)
...ReactionConfig_formValues @relay(mask: false)
...BadgeConfig_formValues @relay(mask: false)
...NewCommenterConfig_formValues @relay(mask: false)
...TopCommenterConfig_formValues @relay(mask: false)
...FlairBadgeConfigContainer_formValues @relay(mask: false)
...FlairBadgeConfigContainer_settings
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Localized } from "@fluent/react/compat";
import React, { FunctionComponent } from "react";
import { graphql } from "react-relay";

import { PlantIcon, SvgIcon } from "coral-ui/components/icons";
import {
FieldSet,
FormField,
FormFieldDescription,
Label,
} from "coral-ui/components/v2";

import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";

// eslint-disable-next-line no-unused-expressions
graphql`
fragment NewCommenterConfig_formValues on Settings {
newCommenter {
enabled
}
}
`;

interface Props {
disabled: boolean;
}

const NewCommenterConfig: FunctionComponent<Props> = ({ disabled }) => (
<ConfigBox
title={
<Localized id="configure-general-newCommenter-title">
<Header container="h2">New commenter</Header>
</Localized>
}
>
<FormFieldDescription>
<Localized
id="configure-general-newCommenter-explanation"
elems={{ icon: <SvgIcon Icon={PlantIcon} /> }}
>
<span>
Add <SvgIcon Icon={PlantIcon} /> badge to commenters who created their
accounts in the past seven days.
</span>
</Localized>
</FormFieldDescription>
<FormField container={<FieldSet />}>
<Localized id="configure-general-newCommenter-enabled">
<Label component="legend">New commenter</Label>
</Localized>
<OnOffField name="newCommenter.enabled" disabled={disabled} />
</FormField>
</ConfigBox>
);

export default NewCommenterConfig;
11 changes: 11 additions & 0 deletions client/src/core/client/stream/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,17 @@ const CLASSES = {
topCommenterStarTooltipDetails:
"coral coral-topCommenter-star-tooltip-details",

/**
* newCommenter is the plant icon shown beside a commenter's username if the New commenter
* feature is enabled and it is a new commenter. This also includes the tooltip that explains the
* new commenter plant icon.
*/
newCommenter: {
plant: "coral coral-newCommenter-plant",
tooltip: "coral coral-newCommenter-plant-tooltip",
tooltipDetails: "coral coral-newCommenter-plant-tooltip-details",
},

/**
* timestamp is the text that contains the time since the comment was
* published.
Expand Down
39 changes: 39 additions & 0 deletions client/src/core/client/stream/tabs/Comments/Comment/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import HTMLContent from "coral-stream/common/HTMLContent";
import Timestamp from "coral-stream/common/Timestamp";
import {
ButtonSvgIcon,
PlantIcon,
RatingStarIcon,
SvgIcon,
} from "coral-ui/components/icons";
Expand Down Expand Up @@ -46,6 +47,8 @@ export interface CommentProps {
enableJumpToParent?: boolean;
featuredCommenter?: boolean | null;
topCommenterEnabled?: boolean | null;
newCommenter?: boolean | null;
newCommenterEnabled?: boolean | null;
}

const Comment: FunctionComponent<CommentProps> = (props) => {
Expand Down Expand Up @@ -77,6 +80,42 @@ const Comment: FunctionComponent<CommentProps> = (props) => {
)}
</MatchMedia>
)}
{props.newCommenterEnabled && props.newCommenter && (
<Flex marginRight={2}>
<div>
<Tooltip
className={CLASSES.comment.topBar.newCommenter.tooltip}
id="newCommenter-tooltip"
title=""
body={
<Localized id="comment-new-commenter-tooltip-details">
<span
className={
CLASSES.comment.topBar.newCommenter.tooltipDetails
}
>
New commenter, say hi
</span>
</Localized>
}
button={({ toggleVisibility, ref }) => (
<Button
onClick={toggleVisibility}
ref={ref}
variant="text"
data-testid="new-user-badge"
>
<ButtonSvgIcon
className={CLASSES.comment.topBar.newCommenter.plant}
Icon={PlantIcon}
filled="currentColor"
/>
</Button>
)}
/>
</div>
</Flex>
)}
{props.topCommenterEnabled && props.featuredCommenter && (
<Flex marginRight={2}>
<div className={styles.featuredStarBorder}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,8 @@ export const CommentContainer: FunctionComponent<Props> = ({
parent={comment.parent}
featuredCommenter={comment.author?.featuredCommenter}
topCommenterEnabled={settings.topCommenter?.enabled}
newCommenter={comment.author?.newCommenter}
newCommenterEnabled={settings.newCommenter?.enabled}
staticUsername={
comment.author && (
<Flex direction="row" alignItems="center" wrap>
Expand Down Expand Up @@ -864,6 +866,7 @@ const enhanced = withShowAuthPopupMutation(
avatar
badges
featuredCommenter
newCommenter
}
parent {
id
Expand Down Expand Up @@ -920,6 +923,9 @@ const enhanced = withShowAuthPopupMutation(
topCommenter {
enabled
}
newCommenter {
enabled
}
featureFlags
...CaretContainer_settings
...EditCommentFormContainer_settings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export interface IndentedCommentProps extends Omit<CommentProps, "ref"> {
username?: string | null;
featuredCommenter?: boolean | null;
topCommenterEnabled?: boolean | null;
newCommenter?: boolean | null;
newCommenterEnabled?: boolean | null;
}

const IndentedComment: FunctionComponent<IndentedCommentProps> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ async function commit(
ignoreable: false,
avatar: viewer.avatar,
featuredCommenter: viewer.featuredCommenter,
newCommenter: viewer.newCommenter,
},
body: input.body || "",
revision: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ graphql`
role
username
featuredCommenter
newCommenter
status {
current
ban {
Expand Down Expand Up @@ -314,6 +315,7 @@ export const CreateCommentMutation = createMutation(
avatar: viewer.avatar,
ignoreable: false,
featuredCommenter: viewer.featuredCommenter,
newCommenter: viewer.newCommenter,
},
site: {
id: uuidGenerator(),
Expand Down
29 changes: 29 additions & 0 deletions client/src/core/client/stream/test/comments/stream/badges.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
commenters,
commentFromMember,
commentFromModerator,
commentFromNewUser,
commentsFromStaff,
settings,
} from "../../fixtures";
Expand Down Expand Up @@ -41,6 +42,10 @@ const storyWithBadgeComments = denormalizeStory(
node: commentFromModerator,
cursor: commentFromModerator.createdAt,
},
{
node: commentFromNewUser,
cursor: commentFromNewUser.createdAt,
},
],
},
},
Expand Down Expand Up @@ -125,4 +130,28 @@ describe("user badges", () => {
"https://wwww.example.com/image.jpg"
);
});

it("renders new user badge if comment by new user", async () => {
const resolvers = createResolversStub<GQLResolver>({
Query: {
stream: () => {
return storyWithBadgeComments;
},
settings: () => {
return { ...settings, newCommenter: { enabled: true } };
},
},
});
await act(async () => {
await createTestRenderer({
resolvers,
});
});

const comment = screen.getByRole("article", {
name: "Comment from Markus 2018-07-06T18:24:00.000Z",
});
const newUserBadge = within(comment).getByTestId("new-user-badge");
expect(newUserBadge).toBeVisible();
});
});
12 changes: 12 additions & 0 deletions client/src/core/client/stream/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export const settings = createFixture<GQLSettings>({
enabled: true,
floatingBellIndicator: true,
},
newCommenter: { enabled: false },
});

export const site = createFixtures<GQLSite>([
Expand Down Expand Up @@ -812,6 +813,17 @@ export const commentFromModerator = denormalizeComment(
)
);

export const commentFromNewUser = denormalizeComment(
createFixture<GQLComment>(
{
id: "comment-from-new-user",
author: { ...commenters[0], newCommenter: true },
body: "Hi I am new",
},
baseComment
)
);

export const commentsFromStaff = denormalizeComments(
createFixtures<GQLComment>(
[
Expand Down
25 changes: 25 additions & 0 deletions client/src/core/client/ui/components/icons/PlantIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { FunctionComponent } from "react";

const PlantIcon: FunctionComponent = () => {
// https://www.streamlinehq.com/icons/streamline-bold/nature-farming/plants/plant
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g id="Plant--Streamline-Ultimate">
<path
d="M10.87 7.85v0.6a0.51 0.51 0 0 0 0.2 0.41 6.81 6.81 0 0 1 2.74 4.61 0.48 0.48 0 0 0 0.26 0.38 0.47 0.47 0 0 0 0.46 0 5.84 5.84 0 0 0 3.17 -5.18 0.5 0.5 0 0 0 -0.5 -0.5 5.82 5.82 0 0 0 -3.92 1.51 0.23 0.23 0 0 1 -0.26 0 0.24 0.24 0 0 1 -0.15 -0.23V7.86a1 1 0 0 1 0.13 -0.54 5.79 5.79 0 0 0 -0.8 -7.17 0.5 0.5 0 0 0 -0.71 0 5.79 5.79 0 0 0 -0.8 7.17 1 1 0 0 1 0.18 0.53Z"
fill="currentcolor"
></path>
<path
d="M12.87 16.78v-2.41A5.85 5.85 0 0 0 7 8.53a0.51 0.51 0 0 0 -0.5 0.5 5.84 5.84 0 0 0 3.7 5.43 1 1 0 0 1 0.64 0.93v2.33a0.26 0.26 0 0 1 -0.16 0.23 0.25 0.25 0 0 1 -0.27 -0.05 7.66 7.66 0 0 0 -5.51 -2.33 0.75 0.75 0 0 0 -0.75 0.75 7.69 7.69 0 0 0 5.59 7.39 0.48 0.48 0 0 0 0.42 -0.08 0.47 0.47 0 0 0 0.19 -0.38 8.67 8.67 0 0 1 2.23 -5.8 1 1 0 0 0 0.29 -0.67Z"
fill="currentcolor"
></path>
<path
d="M19.07 15.57a7.69 7.69 0 0 0 -7.69 7.68 0.75 0.75 0 0 0 0.75 0.75 7.7 7.7 0 0 0 7.69 -7.68 0.75 0.75 0 0 0 -0.75 -0.75Z"
fill="currentcolor"
></path>
</g>
</svg>
);
};

export default PlantIcon;
1 change: 1 addition & 0 deletions client/src/core/client/ui/components/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export { default as NavigationMenuVerticalIcon } from "./NavigationMenuVerticalI
export { default as NotificationBellIcon } from "./NotificationBellIcon";
export { default as PaperWriteIcon } from "./PaperWriteIcon";
export { default as PencilIcon } from "./PencilIcon";
export { default as PlantIcon } from "./PlantIcon";
export { default as QuestionCircleIcon } from "./QuestionCircleIcon";
export { default as QuestionHelpMessageIcon } from "./QuestionHelpMessageIcon";
export { default as RatingHalfStarIcon } from "./RatingHalfStarIcon";
Expand Down
Loading

0 comments on commit 52e96d7

Please sign in to comment.