diff --git a/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-chrome-linux.png b/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-chrome-linux.png
index d5413750a4..18cae0f349 100644
Binary files a/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-chrome-linux.png and b/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-chrome-linux.png differ
diff --git a/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-firefox-linux.png b/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-firefox-linux.png
index 7c62418ffb..8d4544a6ff 100644
Binary files a/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-firefox-linux.png and b/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-firefox-linux.png differ
diff --git a/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-ipad-linux.png b/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-ipad-linux.png
index 76fbd67f91..9cbccdb7ed 100644
Binary files a/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-ipad-linux.png and b/e2e-tests/playwright/specs/visual/channels/intro_channel.spec.ts-snapshots/intro-to-channel-as-regular-user-ipad-linux.png differ
diff --git a/webapp/channels/src/components/__snapshots__/get_link_modal.test.tsx.snap b/webapp/channels/src/components/__snapshots__/get_link_modal.test.tsx.snap
index 1605e40299..ccfe41c9d6 100644
--- a/webapp/channels/src/components/__snapshots__/get_link_modal.test.tsx.snap
+++ b/webapp/channels/src/components/__snapshots__/get_link_modal.test.tsx.snap
@@ -36,11 +36,11 @@ exports[`components/GetLinkModal should have called onHide 1`] = `
closeLabel="Close"
id="getLinkModalLabel"
>
-
title
-
+
-
-
-
+
`;
@@ -131,11 +125,11 @@ exports[`components/GetLinkModal should have called onHide 2`] = `
closeLabel="Close"
id="getLinkModalLabel"
>
-
title
-
+
+
-
title
-
+
+
-
title
-
+
+
{
link: 'https://mattermost.com',
};
+ beforeEach(() => {
+ jest.useFakeTimers();
+ });
+
+ afterEach(() => {
+ jest.useRealTimers();
+ });
+
test('should match snapshot when all props is set', () => {
const helpText = 'help text';
const props = {...requiredProps, helpText};
@@ -68,4 +77,44 @@ describe('components/GetLinkModal', () => {
wrapper.find('#linkModalTextArea').simulate('click');
expect(wrapper.state('copiedLink')).toBe(true);
});
+
+ test('should change button state when copying', () => {
+ const wrapper = mountWithIntl(
+ ,
+ );
+
+ // Initial state
+ expect(wrapper.find('#linkModalCopyLink').text()).toContain('Copy Link');
+ expect(wrapper.find('#linkModalCopyLink').hasClass('btn-primary')).toBe(true);
+ expect(wrapper.find('#linkModalCopyLink').hasClass('btn-success')).toBe(false);
+
+ // After copying
+ wrapper.find('#linkModalCopyLink').simulate('click');
+ expect(wrapper.find('#linkModalCopyLink').text()).toContain('Copied');
+ expect(wrapper.find('#linkModalCopyLink').hasClass('btn-primary')).toBe(true);
+ expect(wrapper.find('#linkModalCopyLink').hasClass('btn-success')).toBe(true);
+
+ // After timeout
+ act(() => {
+ jest.advanceTimersByTime(1000);
+ });
+ wrapper.update();
+ expect(wrapper.find('#linkModalCopyLink').text()).toContain('Copy Link');
+ expect(wrapper.find('#linkModalCopyLink').hasClass('btn-primary')).toBe(true);
+ expect(wrapper.find('#linkModalCopyLink').hasClass('btn-success')).toBe(false);
+ });
+
+ test('should cleanup timeout on unmount', () => {
+ const wrapper = mountWithIntl(
+ ,
+ );
+
+ wrapper.find('#linkModalCopyLink').simulate('click');
+ expect(wrapper.state('copiedLink')).toBe(true);
+
+ wrapper.unmount();
+ jest.advanceTimersByTime(1000);
+
+ // If we get here without errors, the timeout was properly cleaned up
+ });
});
diff --git a/webapp/channels/src/components/get_link_modal.tsx b/webapp/channels/src/components/get_link_modal.tsx
index c656f388e3..b9dd26dd38 100644
--- a/webapp/channels/src/components/get_link_modal.tsx
+++ b/webapp/channels/src/components/get_link_modal.tsx
@@ -5,8 +5,6 @@ import React from 'react';
import {Modal} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
-import SuccessIcon from 'components/widgets/icons/fa_success_icon';
-
type Props = {
show: boolean;
onHide: () => void;
@@ -22,6 +20,7 @@ type State = {
export default class GetLinkModal extends React.PureComponent {
private textAreaRef = React.createRef();
+ private resetTimeout: NodeJS.Timeout | null = null;
public static defaultProps = {
helpText: null,
};
@@ -33,7 +32,16 @@ export default class GetLinkModal extends React.PureComponent {
};
}
+ public componentWillUnmount(): void {
+ if (this.resetTimeout) {
+ clearTimeout(this.resetTimeout);
+ }
+ }
+
public onHide = (): void => {
+ if (this.resetTimeout) {
+ clearTimeout(this.resetTimeout);
+ }
this.setState({copiedLink: false});
this.props.onHide();
};
@@ -47,6 +55,12 @@ export default class GetLinkModal extends React.PureComponent {
try {
this.setState({copiedLink: document.execCommand('copy')});
+ if (this.resetTimeout) {
+ clearTimeout(this.resetTimeout);
+ }
+ this.resetTimeout = setTimeout(() => {
+ this.setState({copiedLink: false});
+ }, 1000);
} catch (err) {
this.setState({copiedLink: false});
}
@@ -73,13 +87,26 @@ export default class GetLinkModal extends React.PureComponent {
id='linkModalCopyLink'
data-copy-btn='true'
type='button'
- className='btn btn-primary pull-left'
+ className={`btn ${this.state.copiedLink ? 'btn-primary btn-success' : 'btn-primary'} pull-left`}
onClick={this.copyLink}
>
-
+ {this.state.copiedLink ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+ >
+ )}
);
}
@@ -96,19 +123,6 @@ export default class GetLinkModal extends React.PureComponent {
/>
);
- let copyLinkConfirm = null;
- if (this.state.copiedLink) {
- copyLinkConfirm = (
-
-
-
-
- );
- }
-
return (
{
id='getLinkModalLabel'
closeButton={true}
>
- {this.props.title}
+ {this.props.title}
{helpText}
@@ -141,7 +155,6 @@ export default class GetLinkModal extends React.PureComponent {
/>
{copyLink}
- {copyLinkConfirm}
);
diff --git a/webapp/channels/src/sass/components/_buttons.scss b/webapp/channels/src/sass/components/_buttons.scss
index ea0f06e8a3..9133bc9e18 100644
--- a/webapp/channels/src/sass/components/_buttons.scss
+++ b/webapp/channels/src/sass/components/_buttons.scss
@@ -230,6 +230,19 @@ button {
color: rgba(var(--center-channel-color-rgb), 0.32) !important;
opacity: 1;
}
+
+ &.btn-success {
+ background-color: var(--online-indicator);
+ color: var(--button-color-rgb);
+
+ &:hover {
+ background-color: var(--online-indicator);
+ }
+
+ &:active {
+ background-color: var(--online-indicator);
+ }
+ }
}
&.btn-secondary {
diff --git a/webapp/channels/src/sass/components/_modal.scss b/webapp/channels/src/sass/components/_modal.scss
index bc6d3d3124..6cd70b3bfd 100644
--- a/webapp/channels/src/sass/components/_modal.scss
+++ b/webapp/channels/src/sass/components/_modal.scss
@@ -328,6 +328,7 @@
background: transparent;
color: functions.v(center-channel-color);
font-size: 22px;
+ font-weight: 600;
line-height: 28px;
word-break: break-word;
}