Skip to content

Commit e9982d7

Browse files
fix: add missing Flow type definition files
1 parent 08a8d1f commit e9982d7

File tree

6 files changed

+360
-0
lines changed

6 files changed

+360
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// @flow
2+
import * as React from 'react';
3+
import { FormattedMessage } from 'react-intl';
4+
import type { MessageDescriptor } from 'react-intl';
5+
import classnames from 'classnames';
6+
import InlineError from '../../../../../components/inline-error';
7+
import PlainButton from '../../../../../components/plain-button';
8+
import './ActivityError.scss';
9+
10+
type Props = {
11+
action?: {
12+
onAction: Function,
13+
text: string,
14+
},
15+
className?: string,
16+
message: MessageDescriptor,
17+
title: MessageDescriptor,
18+
};
19+
20+
const ActivityError = ({ action, message, title, className, ...rest }: Props): React.Node => (
21+
<InlineError
22+
className={classnames('bcs-ActivityError', className)}
23+
title={<FormattedMessage {...title} {...rest} />}
24+
>
25+
<div>
26+
<FormattedMessage {...message} />
27+
</div>
28+
{action ? (
29+
<PlainButton className="bcs-ActivityError-action lnk" onClick={action.onAction} type="button">
30+
{action.text}
31+
</PlainButton>
32+
) : null}
33+
</InlineError>
34+
);
35+
36+
export default ActivityError;
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// @flow
2+
import * as React from 'react';
3+
import noop from 'lodash/noop';
4+
import { FormattedMessage } from 'react-intl';
5+
import CollapsableMessage from './CollapsableMessage';
6+
import formatTaggedMessage from '../../utils/formatTaggedMessage';
7+
import LoadingIndicator from '../../../../../components/loading-indicator';
8+
import messages from './messages';
9+
import ShowOriginalButton from './ShowOriginalButton';
10+
import TranslateButton from './TranslateButton';
11+
import { withFeatureConsumer, isFeatureEnabled } from '../../../../common/feature-checking';
12+
13+
import type { GetProfileUrlCallback } from '../../../../common/flowTypes';
14+
import type { FeatureConfig } from '../../../../common/feature-checking';
15+
16+
import './ActivityMessage.scss';
17+
18+
type Props = {
19+
features: FeatureConfig,
20+
getUserProfileUrl?: GetProfileUrlCallback,
21+
id: string,
22+
isEdited?: boolean,
23+
onTranslate?: Function,
24+
tagged_message: string,
25+
translatedTaggedMessage?: string,
26+
translationEnabled?: boolean,
27+
translationFailed?: ?boolean,
28+
};
29+
30+
type State = {
31+
isLoading?: boolean,
32+
isTranslation?: boolean,
33+
};
34+
35+
class ActivityMessage extends React.Component<Props, State> {
36+
static defaultProps = {
37+
isEdited: false,
38+
translationEnabled: false,
39+
};
40+
41+
state = {
42+
isLoading: false,
43+
isTranslation: false,
44+
};
45+
46+
componentDidUpdate(prevProps: Props): void {
47+
const { translatedTaggedMessage, translationFailed } = this.props;
48+
const { translatedTaggedMessage: prevTaggedMessage, translationFailed: prevTranslationFailed } = prevProps;
49+
50+
if (prevTaggedMessage === translatedTaggedMessage || prevTranslationFailed === translationFailed) {
51+
return;
52+
}
53+
54+
if (translatedTaggedMessage || translationFailed) {
55+
this.setState({ isLoading: false });
56+
}
57+
}
58+
59+
getButton(isTranslation?: boolean): React.Node {
60+
let button = null;
61+
if (isTranslation) {
62+
button = <ShowOriginalButton handleShowOriginal={this.handleShowOriginal} />;
63+
} else {
64+
button = <TranslateButton handleTranslate={this.handleTranslate} />;
65+
}
66+
67+
return button;
68+
}
69+
70+
handleTranslate = (event: SyntheticMouseEvent<>): void => {
71+
const { id, tagged_message, onTranslate = noop, translatedTaggedMessage } = this.props;
72+
if (!translatedTaggedMessage) {
73+
this.setState({ isLoading: true });
74+
onTranslate({ id, tagged_message });
75+
}
76+
77+
this.setState({ isTranslation: true });
78+
event.preventDefault();
79+
};
80+
81+
handleShowOriginal = (event: SyntheticMouseEvent<>): void => {
82+
this.setState({ isTranslation: false });
83+
event.preventDefault();
84+
};
85+
86+
render(): React.Node {
87+
const {
88+
features,
89+
getUserProfileUrl,
90+
id,
91+
isEdited,
92+
tagged_message,
93+
translatedTaggedMessage,
94+
translationEnabled,
95+
} = this.props;
96+
const { isLoading, isTranslation } = this.state;
97+
const commentToDisplay =
98+
translationEnabled && isTranslation && translatedTaggedMessage ? translatedTaggedMessage : tagged_message;
99+
const MessageWrapper = isFeatureEnabled(features, 'activityFeed.collapsableMessages.enabled')
100+
? CollapsableMessage
101+
: React.Fragment;
102+
103+
return isLoading ? (
104+
<div className="bcs-ActivityMessageLoading">
105+
<LoadingIndicator size="small" />
106+
</div>
107+
) : (
108+
<div className="bcs-ActivityMessage">
109+
<MessageWrapper>
110+
{formatTaggedMessage(commentToDisplay, id, false, getUserProfileUrl)}
111+
{isEdited && (
112+
<span className="bcs-ActivityMessage-edited">
113+
<FormattedMessage {...messages.activityMessageEdited} />
114+
</span>
115+
)}
116+
</MessageWrapper>
117+
{translationEnabled ? this.getButton(isTranslation) : null}
118+
</div>
119+
);
120+
}
121+
}
122+
123+
export { ActivityMessage };
124+
export default withFeatureConsumer(ActivityMessage);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// @flow
2+
import * as React from 'react';
3+
import { FormattedMessage } from 'react-intl';
4+
import LabelPill from '../../../../../components/label-pill';
5+
import { COMMENT_STATUS_RESOLVED } from '../../../../../constants';
6+
import messages from './messages';
7+
import type { FeedItemStatus } from '../../../../../common/types/feed';
8+
import './ActivityStatus.scss';
9+
10+
type Props = {
11+
status?: FeedItemStatus,
12+
};
13+
14+
const ActivityStatus = ({ status }: Props): React.Node => {
15+
if (status !== COMMENT_STATUS_RESOLVED) {
16+
return null;
17+
}
18+
19+
return (
20+
<div className="bcs-ActivityStatus" data-testid="bcs-ActivityStatus">
21+
<LabelPill.Pill type="success">
22+
<LabelPill.Text>
23+
<FormattedMessage {...messages.activityStatusResolved} />
24+
</LabelPill.Text>
25+
</LabelPill.Pill>
26+
</div>
27+
);
28+
};
29+
30+
export default ActivityStatus;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// @flow
2+
import * as React from 'react';
3+
import { FormattedMessage } from 'react-intl';
4+
import ActivityDatestamp from '../activity-datestamp';
5+
import Tooltip from '../../../../../components/tooltip';
6+
import messages from './messages';
7+
import './ActivityTimestamp.scss';
8+
9+
type Props = {
10+
date: number, // unix epoch timestamp (new Date().getTime())
11+
};
12+
13+
const ActivityTimestamp = ({ date }: Props) => (
14+
<Tooltip text={<FormattedMessage {...messages.fullDateTime} values={{ time: date }} />}>
15+
<small className="bcs-ActivityTimestamp">
16+
<ActivityDatestamp date={date} />
17+
</small>
18+
</Tooltip>
19+
);
20+
21+
export default ActivityTimestamp;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* @flow
3+
* @file Comment component
4+
*/
5+
6+
import * as React from 'react';
7+
import { FormattedMessage, type MessageDescriptor } from 'react-intl';
8+
9+
import Button from '../../../../../components/button';
10+
import commonMessages from '../../../../common/messages';
11+
import PrimaryButton from '../../../../../components/primary-button';
12+
import { KEYS } from '../../../../../constants';
13+
import { Overlay } from '../../../../../components/flyout';
14+
import { ACTIVITY_TARGETS } from '../../../../common/interactionTargets';
15+
import './DeleteConfirmation.scss';
16+
17+
type Props = {
18+
isOpen: boolean,
19+
message: MessageDescriptor,
20+
onDeleteCancel: Function,
21+
onDeleteConfirm: Function,
22+
};
23+
24+
class DeleteConfirmation extends React.Component<Props> {
25+
onKeyDown = (event: SyntheticKeyboardEvent<>): void => {
26+
const { nativeEvent } = event;
27+
const { isOpen, onDeleteCancel } = this.props;
28+
29+
nativeEvent.stopImmediatePropagation();
30+
31+
switch (event.key) {
32+
case KEYS.escape:
33+
event.stopPropagation();
34+
event.preventDefault();
35+
if (isOpen) {
36+
onDeleteCancel();
37+
}
38+
break;
39+
default:
40+
break;
41+
}
42+
};
43+
44+
render() {
45+
const { isOpen, message, onDeleteCancel, onDeleteConfirm, ...rest } = this.props;
46+
47+
return (
48+
<Overlay
49+
className="be-modal bcs-DeleteConfirmation"
50+
onKeyDown={this.onKeyDown}
51+
role="dialog"
52+
shouldDefaultFocus
53+
shouldOutlineFocus={false}
54+
{...rest}
55+
>
56+
<div className="bcs-DeleteConfirmation-promptMessage">
57+
<FormattedMessage {...message} />
58+
</div>
59+
<div>
60+
<Button
61+
aria-label={commonMessages.cancel.defaultMessage}
62+
className="bcs-DeleteConfirmation-cancel"
63+
onClick={onDeleteCancel}
64+
type="button"
65+
data-resin-target={ACTIVITY_TARGETS.INLINE_DELETE_CANCEL}
66+
>
67+
<FormattedMessage {...commonMessages.cancel} />
68+
</Button>
69+
<PrimaryButton
70+
aria-label={commonMessages.delete.defaultMessage}
71+
className="bcs-DeleteConfirmation-delete"
72+
onClick={onDeleteConfirm}
73+
type="button"
74+
data-resin-target={ACTIVITY_TARGETS.INLINE_DELETE_CONFIRM}
75+
>
76+
<FormattedMessage {...commonMessages.delete} />
77+
</PrimaryButton>
78+
</div>
79+
</Overlay>
80+
);
81+
}
82+
}
83+
84+
export default DeleteConfirmation;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// @flow
2+
import * as React from 'react';
3+
import classnames from 'classnames';
4+
import { Link } from '../../../../../components/link';
5+
import type { GetProfileUrlCallback } from '../../../../common/flowTypes';
6+
import './UserLink.scss';
7+
8+
type Props = {
9+
className?: string,
10+
getUserProfileUrl?: GetProfileUrlCallback,
11+
id: string,
12+
name: string,
13+
};
14+
15+
type State = {
16+
profileUrl?: string,
17+
};
18+
19+
class UserLink extends React.PureComponent<Props, State> {
20+
state = {};
21+
22+
/**
23+
* Success handler for getting profile url
24+
*
25+
* @param {string} profileUrl the user profile url
26+
*/
27+
getProfileUrlHandler = (profileUrl?: string) => {
28+
this.setState({
29+
profileUrl,
30+
});
31+
};
32+
33+
/**
34+
* Gets the profile URL for the user from the getUserProfileUrl prop
35+
*
36+
* @return {Promise} a promise which resolves with the profileUrl string
37+
*/
38+
getUserProfileUrl() {
39+
const { id, getUserProfileUrl }: Props = this.props;
40+
if (!getUserProfileUrl) {
41+
return Promise.resolve();
42+
}
43+
44+
return getUserProfileUrl(id).then(this.getProfileUrlHandler);
45+
}
46+
47+
componentDidMount() {
48+
this.getUserProfileUrl();
49+
}
50+
51+
render() {
52+
const { name, getUserProfileUrl, className, ...rest }: Props = this.props;
53+
const { profileUrl }: State = this.state;
54+
55+
return profileUrl ? (
56+
<Link className={classnames('bcs-UserLink', className)} {...rest} href={profileUrl}>
57+
{name}
58+
</Link>
59+
) : (
60+
<span {...rest}>{name}</span>
61+
);
62+
}
63+
}
64+
65+
export default UserLink;

0 commit comments

Comments
 (0)