refactor: to useCopyToClipboard to catch errors - when user has disable copy clipboard permission in browser (#13330)
as discussed here https://github.com/twentyhq/twenty/issues/13292#issuecomment-3092215050 with @prastoin - [x] introduce optional message param to `copyToClipboard` method in `useCopyToClipboard` and refactor it across app, as in case if user has disallowed clipboard permission in BROWSER unprotected clipboard access breaks without catch. - [x] Email copied to clipboard - [x] run lingui extract
This commit is contained in:
+5
-21
@@ -3,7 +3,6 @@ import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropd
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
@@ -16,7 +15,6 @@ import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||
import { useDeleteViewFromCurrentState } from '@/views/view-picker/hooks/useDeleteViewFromCurrentState';
|
||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
@@ -27,6 +25,7 @@ import {
|
||||
IconTrash,
|
||||
} from 'twenty-ui/display';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
|
||||
|
||||
export const ObjectOptionsDropdownMenuContent = () => {
|
||||
const { t } = useLingui();
|
||||
@@ -62,9 +61,6 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
const theme = useTheme();
|
||||
const { enqueueSuccessSnackBar } = useSnackBar();
|
||||
|
||||
const isDefaultView = currentView?.key === 'INDEX';
|
||||
|
||||
const selectableItemIdArray = [
|
||||
@@ -80,6 +76,8 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
OBJECT_OPTIONS_DROPDOWN_ID,
|
||||
);
|
||||
|
||||
const { copyToClipboard } = useCopyToClipboard();
|
||||
|
||||
return (
|
||||
<DropdownContent>
|
||||
{currentView && (
|
||||
@@ -167,28 +165,14 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
itemId="Copy link to view"
|
||||
onEnter={() => {
|
||||
const currentUrl = window.location.href;
|
||||
navigator.clipboard.writeText(currentUrl);
|
||||
enqueueSuccessSnackBar({
|
||||
message: t`Link copied to clipboard`,
|
||||
options: {
|
||||
icon: <IconCopy size={theme.icon.size.md} />,
|
||||
duration: 2000,
|
||||
},
|
||||
});
|
||||
copyToClipboard(currentUrl, t`Link copied to clipboard`);
|
||||
}}
|
||||
>
|
||||
<MenuItem
|
||||
focused={selectedItemId === 'Copy link to view'}
|
||||
onClick={() => {
|
||||
const currentUrl = window.location.href;
|
||||
navigator.clipboard.writeText(currentUrl);
|
||||
enqueueSuccessSnackBar({
|
||||
message: t`Link copied to clipboard`,
|
||||
options: {
|
||||
icon: <IconCopy size={theme.icon.size.md} />,
|
||||
duration: 2000,
|
||||
},
|
||||
});
|
||||
copyToClipboard(currentUrl, t`Link copied to clipboard`);
|
||||
}}
|
||||
LeftIcon={IconCopy}
|
||||
text={t`Copy link to view`}
|
||||
|
||||
+3
-13
@@ -1,10 +1,8 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { IconCopy } from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
|
||||
|
||||
const StyledButtonContainer = styled.div`
|
||||
padding: 0 ${({ theme }) => theme.spacing(1)};
|
||||
@@ -15,8 +13,7 @@ export type LightCopyIconButtonProps = {
|
||||
};
|
||||
|
||||
export const LightCopyIconButton = ({ copyText }: LightCopyIconButtonProps) => {
|
||||
const { enqueueSuccessSnackBar } = useSnackBar();
|
||||
const theme = useTheme();
|
||||
const { copyToClipboard } = useCopyToClipboard();
|
||||
const { t } = useLingui();
|
||||
|
||||
return (
|
||||
@@ -24,14 +21,7 @@ export const LightCopyIconButton = ({ copyText }: LightCopyIconButtonProps) => {
|
||||
<LightIconButton
|
||||
Icon={IconCopy}
|
||||
onClick={() => {
|
||||
enqueueSuccessSnackBar({
|
||||
message: t`Text copied to clipboard`,
|
||||
options: {
|
||||
icon: <IconCopy size={theme.icon.size.md} />,
|
||||
duration: 2000,
|
||||
},
|
||||
});
|
||||
navigator.clipboard.writeText(copyText);
|
||||
copyToClipboard(copyText, t`Text copied to clipboard`);
|
||||
}}
|
||||
aria-label="Copy to Clipboard"
|
||||
/>
|
||||
|
||||
+3
-1
@@ -3,6 +3,7 @@ import { EmailsFieldMenuItem } from '@/object-record/record-field/meta-types/inp
|
||||
import { recordFieldInputIsFieldInErrorComponentState } from '@/object-record/record-field/states/recordFieldInputIsFieldInErrorComponentState';
|
||||
import { emailSchema } from '@/object-record/record-field/validation-schemas/emailSchema';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
@@ -20,6 +21,7 @@ export const EmailsFieldInput = ({
|
||||
}: EmailsFieldInputProps) => {
|
||||
const { persistEmailsField, fieldValue } = useEmailsField();
|
||||
const { copyToClipboard } = useCopyToClipboard();
|
||||
const { t } = useLingui();
|
||||
|
||||
const emails = useMemo<string[]>(
|
||||
() =>
|
||||
@@ -59,7 +61,7 @@ export const EmailsFieldInput = ({
|
||||
};
|
||||
|
||||
const handleCopy = (email: string) => {
|
||||
copyToClipboard(email);
|
||||
copyToClipboard(email, t`Email copied to clipboard`);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user