Skip to content

Commit 2730b3e

Browse files
authored
copy to clipboard on MultiItemFieldMenuItem (#13292)
# ISSUE - closes #13089
1 parent ac8dab2 commit 2730b3e

File tree

4 files changed

+37
-0
lines changed

4 files changed

+37
-0
lines changed

packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/EmailsFieldInput.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta
66
import { useCallback, useMemo } from 'react';
77
import { isDefined } from 'twenty-shared/utils';
88
import { FieldMetadataType } from '~/generated-metadata/graphql';
9+
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
910
import { MultiItemFieldInput } from './MultiItemFieldInput';
1011

1112
type EmailsFieldInputProps = {
@@ -18,6 +19,7 @@ export const EmailsFieldInput = ({
1819
onClickOutside,
1920
}: EmailsFieldInputProps) => {
2021
const { persistEmailsField, fieldValue } = useEmailsField();
22+
const { copyToClipboard } = useCopyToClipboard();
2123

2224
const emails = useMemo<string[]>(
2325
() =>
@@ -56,6 +58,10 @@ export const EmailsFieldInput = ({
5658
setIsFieldInError(hasError && values.length === 0);
5759
};
5860

61+
const handleCopy = (email: string) => {
62+
copyToClipboard(email);
63+
};
64+
5965
return (
6066
<MultiItemFieldInput
6167
items={emails}
@@ -80,10 +86,12 @@ export const EmailsFieldInput = ({
8086
dropdownId={`emails-${index}`}
8187
showPrimaryIcon={getShowPrimaryIcon(index)}
8288
showSetAsPrimaryButton={getShowSetAsPrimaryButton(index)}
89+
showCopyButton={true}
8390
email={email}
8491
onEdit={handleEdit}
8592
onSetAsPrimary={handleSetPrimary}
8693
onDelete={handleDelete}
94+
onCopy={handleCopy}
8795
/>
8896
)}
8997
onError={handleError}

packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/EmailsFieldMenuItem.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ type EmailsFieldMenuItemProps = {
66
onEdit?: () => void;
77
onSetAsPrimary?: () => void;
88
onDelete?: () => void;
9+
onCopy?: (email: string) => void;
910
email: string;
1011
showPrimaryIcon: boolean;
1112
showSetAsPrimaryButton: boolean;
13+
showCopyButton: boolean;
1214
};
1315

1416
export const EmailsFieldMenuItem = ({
@@ -19,6 +21,8 @@ export const EmailsFieldMenuItem = ({
1921
email,
2022
showPrimaryIcon,
2123
showSetAsPrimaryButton,
24+
showCopyButton,
25+
onCopy,
2226
}: EmailsFieldMenuItemProps) => {
2327
return (
2428
<MultiItemFieldMenuItem
@@ -30,6 +34,8 @@ export const EmailsFieldMenuItem = ({
3034
DisplayComponent={EmailDisplay}
3135
showPrimaryIcon={showPrimaryIcon}
3236
showSetAsPrimaryButton={showSetAsPrimaryButton}
37+
showCopyButton={showCopyButton}
38+
onCopy={onCopy}
3339
/>
3440
);
3541
};

packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldMenuItem.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import React, { useState } from 'react';
88
import {
99
IconBookmark,
1010
IconBookmarkPlus,
11+
IconCopy,
1112
IconPencil,
1213
IconTrash,
1314
} from 'twenty-ui/display';
@@ -19,9 +20,11 @@ type MultiItemFieldMenuItemProps<T> = {
1920
onEdit?: () => void;
2021
onSetAsPrimary?: () => void;
2122
onDelete?: () => void;
23+
onCopy?: (value: T) => void;
2224
DisplayComponent: React.ComponentType<{ value: T }>;
2325
showPrimaryIcon: boolean;
2426
showSetAsPrimaryButton: boolean;
27+
showCopyButton?: boolean;
2528
};
2629

2730
export const MultiItemFieldMenuItem = <T,>({
@@ -33,6 +36,8 @@ export const MultiItemFieldMenuItem = <T,>({
3336
DisplayComponent,
3437
showPrimaryIcon,
3538
showSetAsPrimaryButton,
39+
showCopyButton,
40+
onCopy,
3641
}: MultiItemFieldMenuItemProps<T>) => {
3742
const [isHovered, setIsHovered] = useState(false);
3843
const { closeDropdown } = useCloseDropdown();
@@ -71,6 +76,14 @@ export const MultiItemFieldMenuItem = <T,>({
7176
onEdit?.();
7277
};
7378

79+
const handleCopyClick = (event: React.MouseEvent<HTMLDivElement>) => {
80+
event.stopPropagation();
81+
event.preventDefault();
82+
83+
closeDropdown(dropdownId);
84+
onCopy?.(value);
85+
};
86+
7487
return (
7588
<MenuItemWithOptionDropdown
7689
onMouseEnter={handleMouseEnter}
@@ -100,6 +113,13 @@ export const MultiItemFieldMenuItem = <T,>({
100113
text="Delete"
101114
onClick={handleDeleteClick}
102115
/>
116+
{showCopyButton && (
117+
<MenuItem
118+
LeftIcon={IconCopy}
119+
text="Copy"
120+
onClick={handleCopyClick}
121+
/>
122+
)}
103123
</DropdownMenuItemsContainer>
104124
</DropdownContent>
105125
}

packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/EmailsFieldInput.stories.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFi
1313
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
1414
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
1515
import { FieldMetadataType } from '~/generated-metadata/graphql';
16+
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
17+
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
1618
import { EmailsFieldInput } from '../EmailsFieldInput';
1719

1820
const updateRecord = fn();
@@ -113,6 +115,7 @@ const EmailInputWithContext = ({
113115
const meta: Meta<typeof EmailInputWithContext> = {
114116
title: 'UI/Input/EmailsFieldInput',
115117
component: EmailInputWithContext,
118+
decorators: [SnackBarDecorator, I18nFrontDecorator],
116119
};
117120

118121
export default meta;

0 commit comments

Comments
 (0)