Skip to content

Commit 8742f1b

Browse files
authored
feat(content-sidebar): Add in beta feedback task modal component (#1034)
* feat(content-sidebar): Add in beta feedback task modal component Create reusable component, and use it for the content sidebar. - Add snapshot test for component - use message module over inline messages - add examples and flow-typed definition
1 parent 5d9ed9c commit 8742f1b

File tree

12 files changed

+178
-4
lines changed

12 files changed

+178
-4
lines changed

examples/src/features.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export default {
44
tasks: {
55
createFromComment: true,
66
createButton: true,
7+
feedbackUrl: 'http://example.org/',
78
newApi: true,
89
newCards: true,
910
},

flow-typed/box-ui-elements.js

+1
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,7 @@ type ActivityFeedFeatures = {
952952
tasks?: {|
953953
createButton?: boolean, // Show the Create Task button (requires newApi)
954954
createFromComment?: boolean, // Show the Add Task checkbox
955+
feedbackUrl?: string, // URL used for feedback form for tasks
955956
newApi?: boolean, // Use new service
956957
newCards?: boolean, // Show new task card layout (requires on newApi)
957958
|},

i18n/en-US.properties

+4
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ be.executeIntegrationOpenWithErrorSubHeader = Please try again later.
132132
be.expand = Expand
133133
# Label for face skill section in the preview sidebar
134134
be.faceSkill = Faces
135+
# Call-to-action text describing what to do to navigate to specified feedback form
136+
be.feedbackCtaText = Click to provide feedback
137+
# Accessible text used to describe the form used for feedback
138+
be.feedbackFormDescription = Beta Feedback Form
135139
# File access stats error message
136140
be.fileAccessStatsErrorHeaderMessage = Something went wrong when fetching the access stats.
137141
# File classification error message

src/elements/content-sidebar/ActivitySidebar.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import flow from 'lodash/flow';
1111
import messages from '../common/messages';
1212
import { withAPIContext } from '../common/api-context';
1313
import { withErrorBoundary } from '../common/error-boundary';
14-
import { FeatureFlag, withFeatureConsumer, isFeatureEnabled } from '../common/feature-checking';
14+
import { FeatureFlag, withFeatureConsumer, isFeatureEnabled, getFeatureConfig } from '../common/feature-checking';
1515
import { getBadUserError, getBadItemError } from '../../utils/error';
1616
import API from '../../api';
1717
import { withLogger } from '../common/logger';
@@ -533,7 +533,7 @@ class ActivitySidebar extends React.PureComponent<Props, State> {
533533
};
534534

535535
renderAddTaskButton = () => {
536-
const { isDisabled } = this.props;
536+
const { isDisabled, features } = this.props;
537537
const { approverSelectorContacts } = this.state;
538538
const {
539539
getApproverWithQuery,
@@ -546,6 +546,7 @@ class ActivitySidebar extends React.PureComponent<Props, State> {
546546
getApproverWithQuery,
547547
approverSelectorContacts,
548548
getAvatarUrl,
549+
feedbackUrl: getFeatureConfig(features, 'activityFeed.tasks').feedbackUrl || '',
549550
};
550551
return (
551552
<FeatureFlag feature="activityFeed.tasks.newApi">

src/elements/content-sidebar/AddTaskButton.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// @flow
22
import * as React from 'react';
33
import { FormattedMessage } from 'react-intl';
4+
import BetaFeedbackBadge from '../../features/beta-feedback';
45
import Button from '../../components/button';
56
import Modal from '../../components/modal/Modal';
67
import TaskForm from './activity-feed/task-form';
78
import messages from '../common/messages';
89

910
type AddTaskButtonProps = {|
11+
feedbackUrl: string,
1012
isDisabled: boolean,
1113
|};
1214

@@ -41,7 +43,7 @@ class AddTaskButton extends React.Component<Props, State> {
4143
handleSubmit = () => this.setState({ isTaskFormOpen: false });
4244

4345
render() {
44-
const { isDisabled, ...passThrough } = this.props;
46+
const { isDisabled, feedbackUrl, ...passThrough } = this.props;
4547
const { isTaskFormOpen } = this.state;
4648

4749
return (
@@ -54,7 +56,12 @@ class AddTaskButton extends React.Component<Props, State> {
5456
data-testid="create-task-modal"
5557
isOpen={isTaskFormOpen}
5658
onRequestClose={this.handleClose}
57-
title={<FormattedMessage {...messages.tasksAddTaskFormTitle} />}
59+
title={
60+
<React.Fragment>
61+
<FormattedMessage {...messages.tasksAddTaskFormTitle} />
62+
<BetaFeedbackBadge tooltip formUrl={feedbackUrl} />
63+
</React.Fragment>
64+
}
5865
>
5966
<div className="be">
6067
<TaskForm {...passThrough} onCancel={this.handleClose} onSubmit={this.handleSubmit} />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// @flow
2+
import classNames from 'classnames';
3+
import * as React from 'react';
4+
import { FormattedMessage } from 'react-intl';
5+
6+
import { BetaBadge } from '../../components/badge';
7+
import { Link } from '../../components/link';
8+
import Tooltip from '../../components/tooltip/Tooltip';
9+
10+
import messages from './messages';
11+
12+
import './styles/BetaFeedbackBadge.scss';
13+
14+
type Props = {
15+
className?: string,
16+
formUrl: string,
17+
tooltip?: boolean,
18+
};
19+
20+
const BetaFeedbackBadge = ({ className = '', tooltip = false, ...rest }: Props) => {
21+
const classes = classNames('bdl-HeaderFeedbackBadge', className);
22+
const { formUrl } = rest;
23+
const badge = tooltip ? (
24+
<Tooltip text={<FormattedMessage {...messages.feedbackCtaText} />} position="middle-right">
25+
<BetaBadge aria-hidden className="bdl-HeaderFeedbackBadge-betaBadge" />
26+
</Tooltip>
27+
) : (
28+
<BetaBadge className="bdl-HeaderFeedbackBadge-betaBadge" />
29+
);
30+
31+
// TODO: tooltip may require constrainToScrollParent & constrainToWindow in some contexts
32+
return (
33+
<span className={classes}>
34+
<span id="bdl-HeaderFeedbackBadge-ariaLabel" aria-hidden="true" hidden>
35+
<FormattedMessage {...messages.feedbackFormDescription} />
36+
</span>
37+
<Link href={formUrl} target="_blank" aria-labelledBy="bdl-HeaderFeedbackBadge-ariaLabel">
38+
{badge}
39+
</Link>
40+
</span>
41+
);
42+
};
43+
44+
export default BetaFeedbackBadge;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react';
2+
3+
import BetaFeedbackBadge from '../BetaFeedbackBadge';
4+
5+
describe('features/beta-feedback/BetaFeedbackBadge', () => {
6+
const getWrapper = (
7+
props = {
8+
formUrl: 'http://example.org/',
9+
},
10+
) => shallow(<BetaFeedbackBadge {...props} />);
11+
12+
test('should render default component', () => {
13+
const component = getWrapper();
14+
15+
expect(component).toMatchSnapshot();
16+
});
17+
18+
test('should render component with tooltip as requested', () => {
19+
const component = getWrapper({ tooltip: true });
20+
21+
expect(component).toMatchSnapshot();
22+
});
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`features/beta-feedback/BetaFeedbackBadge should render component with tooltip as requested 1`] = `
4+
<span
5+
className="bdl-HeaderFeedbackBadge"
6+
>
7+
<span
8+
aria-hidden="true"
9+
hidden={true}
10+
id="bdl-HeaderFeedbackBadge-ariaLabel"
11+
>
12+
<FormattedMessage
13+
defaultMessage="Beta Feedback Form"
14+
id="be.feedbackFormDescription"
15+
/>
16+
</span>
17+
<Link
18+
aria-labelledBy="bdl-HeaderFeedbackBadge-ariaLabel"
19+
className=""
20+
target="_blank"
21+
>
22+
<Tooltip
23+
constrainToScrollParent={false}
24+
constrainToWindow={true}
25+
position="middle-right"
26+
text={
27+
<FormattedMessage
28+
defaultMessage="Click to provide feedback"
29+
id="be.feedbackCtaText"
30+
/>
31+
}
32+
theme="default"
33+
>
34+
<BetaBadge
35+
aria-hidden={true}
36+
className="bdl-HeaderFeedbackBadge-betaBadge"
37+
/>
38+
</Tooltip>
39+
</Link>
40+
</span>
41+
`;
42+
43+
exports[`features/beta-feedback/BetaFeedbackBadge should render default component 1`] = `
44+
<span
45+
className="bdl-HeaderFeedbackBadge"
46+
>
47+
<span
48+
aria-hidden="true"
49+
hidden={true}
50+
id="bdl-HeaderFeedbackBadge-ariaLabel"
51+
>
52+
<FormattedMessage
53+
defaultMessage="Beta Feedback Form"
54+
id="be.feedbackFormDescription"
55+
/>
56+
</span>
57+
<Link
58+
aria-labelledBy="bdl-HeaderFeedbackBadge-ariaLabel"
59+
className=""
60+
href="http://example.org/"
61+
target="_blank"
62+
>
63+
<BetaBadge
64+
className="bdl-HeaderFeedbackBadge-betaBadge"
65+
/>
66+
</Link>
67+
</span>
68+
`;

src/features/beta-feedback/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './BetaFeedbackBadge';
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { defineMessages } from 'react-intl';
2+
3+
const messages = defineMessages({
4+
feedbackCtaText: {
5+
defaultMessage: 'Click to provide feedback',
6+
description: 'Call-to-action text describing what to do to navigate to specified feedback form',
7+
id: 'be.feedbackCtaText',
8+
},
9+
feedbackFormDescription: {
10+
defaultMessage: 'Beta Feedback Form',
11+
description: 'Accessible text used to describe the form used for feedback',
12+
id: 'be.feedbackFormDescription',
13+
},
14+
});
15+
16+
export default messages;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.bdl-HeaderFeedbackBadge {
2+
margin-left: 4px;
3+
}
4+
5+
.bdl-HeaderFeedbackBadge-betaBadge {
6+
transform: translateY(-3px);
7+
}

test/sidebar.html

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
tasks: {
159159
createButton: true,
160160
createFromComment: true,
161+
feedbackUrl: 'http://example.org/',
161162
newApi: true,
162163
newCards: true,
163164
},

0 commit comments

Comments
 (0)