Skip to content

Commit

Permalink
[web] Update button label after successful copy
Browse files Browse the repository at this point in the history
Summary:
Change button label after successful action.

Depends on D8246

Test Plan:
Click copy button and check if the label changes.
Click it repeatedly and check if the label changes back only after 2s. from the last click.
Click it and close modal - nothing should break.

Reviewers: bartek, kamil, inka

Reviewed By: kamil

Subscribers: ashoat

Differential Revision: https://phab.comm.dev/D8294
  • Loading branch information
palys-swm committed Jun 27, 2023
1 parent dbfb73e commit 9bfaa6d
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 17 deletions.
26 changes: 26 additions & 0 deletions lib/hooks/useResettingState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// @flow

import _debounce from 'lodash/debounce.js';
import * as React from 'react';

import type { SetState } from '../types/hook-types.js';

function useResettingState<T>(
initialState: (() => T) | T,
duration: number,
): [T, SetState<T>] {
const [value, setValue] = React.useState(initialState);
const resetStatusAfterTimeout = React.useRef(
_debounce(() => setValue(initialState), duration),
);
React.useEffect(() => resetStatusAfterTimeout.current.cancel, []);

const setNewValue = React.useCallback((newValue: (T => T) | T) => {
setValue(newValue);
resetStatusAfterTimeout.current();
}, []);

return React.useMemo(() => [value, setNewValue], [setNewValue, value]);
}

export { useResettingState };
17 changes: 13 additions & 4 deletions web/invite-links/view-invite-link-modal.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as React from 'react';
import { useModalContext } from 'lib/components/modal-provider.react.js';
import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
import { inviteLinkUrl } from 'lib/facts/links.js';
import { useResettingState } from 'lib/hooks/useResettingState.js';
import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
import type { InviteLink } from 'lib/types/link-types.js';
import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js';
Expand All @@ -18,6 +19,7 @@ type Props = {
+inviteLink: InviteLink,
};

const copiedMessageDurationMs = 2000;
function ViewInviteLinkModal(props: Props): React.Node {
const { inviteLink } = props;
const threadInfo = useSelector(
Expand All @@ -27,9 +29,16 @@ function ViewInviteLinkModal(props: Props): React.Node {
const { popModal } = useModalContext();

const url = inviteLinkUrl(inviteLink.name);
const copyLink = React.useCallback(() => {
navigator.clipboard.writeText(url);
}, [url]);
const [copied, setCopied] = useResettingState(false, copiedMessageDurationMs);
const copyLink = React.useCallback(async () => {
try {
await navigator.clipboard.writeText(url);
setCopied(true);
} catch (e) {
setCopied(false);
}
}, [setCopied, url]);
const buttonText = copied ? 'Copied!' : 'Copy';

return (
<Modal
Expand All @@ -46,7 +55,7 @@ function ViewInviteLinkModal(props: Props): React.Node {
<div className={css.linkUrl}>{url}</div>
<Button className={css.linkCopyButton} onClick={copyLink}>
<SWMansionIcon icon="link" size={24} />
Copy
{buttonText}
</Button>
</div>
</div>
Expand Down
19 changes: 6 additions & 13 deletions web/utils/tooltip-action-utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// @flow

import invariant from 'invariant';
import _debounce from 'lodash/debounce.js';
import * as React from 'react';

import { useModalContext } from 'lib/components/modal-provider.react.js';
import { useResettingState } from 'lib/hooks/useResettingState.js';
import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
import { useCanEditMessage } from 'lib/shared/edit-messages-utils.js';
import { createMessageReply } from 'lib/shared/message-utils.js';
Expand Down Expand Up @@ -120,18 +120,11 @@ function useMessageCopyAction(
): ?MessageTooltipAction {
const { messageInfo } = item;

const [successful, setSuccessful] = React.useState(false);
const resetStatusAfterTimeout = React.useRef(
_debounce(() => setSuccessful(false), copiedMessageDurationMs),
const [successful, setSuccessful] = useResettingState(
false,
copiedMessageDurationMs,
);

const onSuccess = React.useCallback(() => {
setSuccessful(true);
resetStatusAfterTimeout.current();
}, []);

React.useEffect(() => resetStatusAfterTimeout.current.cancel, []);

return React.useMemo(() => {
if (messageInfo.type !== messageTypes.TEXT) {
return null;
Expand All @@ -140,7 +133,7 @@ function useMessageCopyAction(
const onClick = async () => {
try {
await navigator.clipboard.writeText(messageInfo.text);
onSuccess();
setSuccessful(true);
} catch (e) {
setSuccessful(false);
}
Expand All @@ -150,7 +143,7 @@ function useMessageCopyAction(
onClick,
label: successful ? 'Copied!' : 'Copy',
};
}, [messageInfo.text, messageInfo.type, onSuccess, successful]);
}, [messageInfo.text, messageInfo.type, setSuccessful, successful]);
}

function useMessageReactAction(
Expand Down

0 comments on commit 9bfaa6d

Please sign in to comment.