Skip to content

Commit 92d0ddb

Browse files
authored
feat(threaded-replies): Create RepliesToggle component (#3294)
* feat(threaded-replies): Create RepliesToggle component * feat(threaded-replies): Add tests * feat(threaded-replies): Add stylesheet * feat(threaded-replies): Update test remove loading prop * feat(threaded-replies): Remove alwaysExpanded prop
1 parent f9d4130 commit 92d0ddb

File tree

5 files changed

+144
-0
lines changed

5 files changed

+144
-0
lines changed

i18n/en-US.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,14 @@ be.contentSidebar.activityFeed.comment.commentPostedFullDateTime = {time, date,
176176
be.contentSidebar.activityFeed.comment.commentResolveMenuItem = Resolve
177177
# Text to show on menu item to unresolve the comment
178178
be.contentSidebar.activityFeed.comment.commentUnresolveMenuItem = Unresolve
179+
# Text to show to hide more replies of comment or annotation
180+
be.contentSidebar.activityFeed.comment.hideReplies = Hide replies
179181
# Text to show on button to start replying to comment
180182
be.contentSidebar.activityFeed.comment.reply = Reply
181183
# Text to show on reply form input placeholder
182184
be.contentSidebar.activityFeed.comment.replyInThread = Reply in thread
185+
# Text to show to get more replies of comment or annotation
186+
be.contentSidebar.activityFeed.comment.showReplies = See {repliesToLoadCount, plural, one {# reply} other {# replies}}
183187
# Placeholder for approvers input
184188
be.contentSidebar.activityFeed.commentForm.approvalAddAssignee = Add an assignee
185189
# Label for checkbox to add approvers to a comment
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// @flow
2+
import * as React from 'react';
3+
import { FormattedMessage } from 'react-intl';
4+
5+
import messages from './messages';
6+
import PlainButton from '../../../../components/plain-button';
7+
8+
import './RepliesToggle.scss';
9+
10+
type Props = {
11+
onHideReplies: (index: number) => void,
12+
onShowReplies: () => void,
13+
repliesShownCount: number,
14+
repliesTotalCount: number,
15+
};
16+
17+
const RepliesToggle = ({ onShowReplies, onHideReplies, repliesShownCount, repliesTotalCount }: Props) => {
18+
if (repliesTotalCount <= 1) {
19+
return null;
20+
}
21+
22+
const hasMoreRepliesToShow = repliesTotalCount > repliesShownCount;
23+
const toggleMessage = hasMoreRepliesToShow ? messages.showReplies : messages.hideReplies;
24+
const repliesToLoadCount = Math.max(repliesTotalCount - repliesShownCount, 0);
25+
26+
const handleToggle = () => {
27+
if (hasMoreRepliesToShow) {
28+
onShowReplies();
29+
} else if (repliesShownCount) {
30+
onHideReplies(repliesShownCount - 1);
31+
}
32+
};
33+
34+
return (
35+
<PlainButton className="bcs-RepliesToggle" onClick={handleToggle} type="button">
36+
<FormattedMessage values={{ repliesToLoadCount }} {...toggleMessage} />
37+
</PlainButton>
38+
);
39+
};
40+
41+
export default RepliesToggle;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@import '../../../common/variables';
2+
3+
.bcs-RepliesToggle {
4+
margin-bottom: $bdl-grid-unit * 4;
5+
color: $bdl-box-blue;
6+
font-weight: bold;
7+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// @flow
2+
3+
import React from 'react';
4+
import { IntlProvider } from 'react-intl';
5+
import { fireEvent, render, screen } from '@testing-library/react';
6+
import RepliesToggle from '../RepliesToggle';
7+
8+
jest.mock('react-intl', () => ({
9+
...jest.requireActual('react-intl'),
10+
}));
11+
12+
const showReplies = jest.fn();
13+
const hideReplies = jest.fn();
14+
const shownCount = 1;
15+
const totalCount = 9;
16+
17+
const getWrapper = props =>
18+
render(
19+
<IntlProvider locale="en">
20+
<RepliesToggle
21+
id="123"
22+
isRepliesLoading={false}
23+
onShowReplies={showReplies}
24+
onHideReplies={hideReplies}
25+
repliesShownCount={shownCount}
26+
repliesTotalCount={totalCount}
27+
{...props}
28+
/>
29+
</IntlProvider>,
30+
);
31+
32+
describe('elements/content-sidebar/ActivityFeed/comment/RepliesToggle', () => {
33+
test('should correctly render show toggle', () => {
34+
const countDifference = totalCount - 1;
35+
36+
getWrapper();
37+
38+
expect(screen.getByText(`See ${countDifference} replies`)).toBeVisible();
39+
expect(screen.queryByText('Hide replies')).not.toBeInTheDocument();
40+
41+
fireEvent.click(screen.getByText(`See ${countDifference} replies`));
42+
43+
expect(showReplies).toBeCalledTimes(1);
44+
expect(hideReplies).not.toBeCalled();
45+
});
46+
47+
test.each`
48+
repliesShownCount | repliesTotalCount
49+
${3} | ${3}
50+
${3} | ${2}
51+
`(
52+
`Should correctly render hide toggle when shown count is $repliesShownCount and total count is $repliesTotalCount`,
53+
({ repliesShownCount, repliesTotalCount }) => {
54+
getWrapper({ repliesShownCount, repliesTotalCount });
55+
56+
expect(screen.getByText('Hide replies')).toBeVisible();
57+
expect(screen.queryByText(`See ${repliesTotalCount - 1} replies`)).not.toBeInTheDocument();
58+
59+
fireEvent.click(screen.getByText(`Hide replies`));
60+
61+
expect(hideReplies).toBeCalledTimes(1);
62+
expect(hideReplies).toBeCalledWith(repliesShownCount - 1);
63+
expect(showReplies).not.toBeCalled();
64+
},
65+
);
66+
67+
test.each`
68+
repliesShownCount | repliesTotalCount
69+
${3} | ${1}
70+
${3} | ${0}
71+
${1} | ${0}
72+
${1} | ${1}
73+
`(
74+
`Should not render toggle when shown count is $repliesShownCount and total count is $repliesTotalCount`,
75+
({ repliesShownCount, repliesTotalCount }) => {
76+
getWrapper({ repliesShownCount, repliesTotalCount });
77+
78+
expect(screen.queryByText(`Hide replies`)).not.toBeInTheDocument();
79+
expect(screen.queryByText(`See ${repliesTotalCount} replies`)).not.toBeInTheDocument();
80+
},
81+
);
82+
});

src/elements/content-sidebar/activity-feed/comment/messages.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ const messages = defineMessages({
4747
defaultMessage: 'Reply in thread',
4848
description: 'Text to show on reply form input placeholder',
4949
},
50+
hideReplies: {
51+
id: 'be.contentSidebar.activityFeed.comment.hideReplies',
52+
defaultMessage: 'Hide replies',
53+
description: 'Text to show to hide more replies of comment or annotation',
54+
},
55+
showReplies: {
56+
id: 'be.contentSidebar.activityFeed.comment.showReplies',
57+
defaultMessage: 'See {repliesToLoadCount, plural, one {# reply} other {# replies}}',
58+
description: 'Text to show to get more replies of comment or annotation',
59+
},
5060
});
5161

5262
export default messages;

0 commit comments

Comments
 (0)