copy to clipboard on MultiItemFieldMenuItem (#13292)
# ISSUE - closes #13089
This commit is contained in:
@ -6,6 +6,7 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
|
||||||
import { MultiItemFieldInput } from './MultiItemFieldInput';
|
import { MultiItemFieldInput } from './MultiItemFieldInput';
|
||||||
|
|
||||||
type EmailsFieldInputProps = {
|
type EmailsFieldInputProps = {
|
||||||
@ -18,6 +19,7 @@ export const EmailsFieldInput = ({
|
|||||||
onClickOutside,
|
onClickOutside,
|
||||||
}: EmailsFieldInputProps) => {
|
}: EmailsFieldInputProps) => {
|
||||||
const { persistEmailsField, fieldValue } = useEmailsField();
|
const { persistEmailsField, fieldValue } = useEmailsField();
|
||||||
|
const { copyToClipboard } = useCopyToClipboard();
|
||||||
|
|
||||||
const emails = useMemo<string[]>(
|
const emails = useMemo<string[]>(
|
||||||
() =>
|
() =>
|
||||||
@ -56,6 +58,10 @@ export const EmailsFieldInput = ({
|
|||||||
setIsFieldInError(hasError && values.length === 0);
|
setIsFieldInError(hasError && values.length === 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCopy = (email: string) => {
|
||||||
|
copyToClipboard(email);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultiItemFieldInput
|
<MultiItemFieldInput
|
||||||
items={emails}
|
items={emails}
|
||||||
@ -80,10 +86,12 @@ export const EmailsFieldInput = ({
|
|||||||
dropdownId={`emails-${index}`}
|
dropdownId={`emails-${index}`}
|
||||||
showPrimaryIcon={getShowPrimaryIcon(index)}
|
showPrimaryIcon={getShowPrimaryIcon(index)}
|
||||||
showSetAsPrimaryButton={getShowSetAsPrimaryButton(index)}
|
showSetAsPrimaryButton={getShowSetAsPrimaryButton(index)}
|
||||||
|
showCopyButton={true}
|
||||||
email={email}
|
email={email}
|
||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
onSetAsPrimary={handleSetPrimary}
|
onSetAsPrimary={handleSetPrimary}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
|
onCopy={handleCopy}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
onError={handleError}
|
onError={handleError}
|
||||||
|
|||||||
@ -6,9 +6,11 @@ type EmailsFieldMenuItemProps = {
|
|||||||
onEdit?: () => void;
|
onEdit?: () => void;
|
||||||
onSetAsPrimary?: () => void;
|
onSetAsPrimary?: () => void;
|
||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
|
onCopy?: (email: string) => void;
|
||||||
email: string;
|
email: string;
|
||||||
showPrimaryIcon: boolean;
|
showPrimaryIcon: boolean;
|
||||||
showSetAsPrimaryButton: boolean;
|
showSetAsPrimaryButton: boolean;
|
||||||
|
showCopyButton: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EmailsFieldMenuItem = ({
|
export const EmailsFieldMenuItem = ({
|
||||||
@ -19,6 +21,8 @@ export const EmailsFieldMenuItem = ({
|
|||||||
email,
|
email,
|
||||||
showPrimaryIcon,
|
showPrimaryIcon,
|
||||||
showSetAsPrimaryButton,
|
showSetAsPrimaryButton,
|
||||||
|
showCopyButton,
|
||||||
|
onCopy,
|
||||||
}: EmailsFieldMenuItemProps) => {
|
}: EmailsFieldMenuItemProps) => {
|
||||||
return (
|
return (
|
||||||
<MultiItemFieldMenuItem
|
<MultiItemFieldMenuItem
|
||||||
@ -30,6 +34,8 @@ export const EmailsFieldMenuItem = ({
|
|||||||
DisplayComponent={EmailDisplay}
|
DisplayComponent={EmailDisplay}
|
||||||
showPrimaryIcon={showPrimaryIcon}
|
showPrimaryIcon={showPrimaryIcon}
|
||||||
showSetAsPrimaryButton={showSetAsPrimaryButton}
|
showSetAsPrimaryButton={showSetAsPrimaryButton}
|
||||||
|
showCopyButton={showCopyButton}
|
||||||
|
onCopy={onCopy}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import React, { useState } from 'react';
|
|||||||
import {
|
import {
|
||||||
IconBookmark,
|
IconBookmark,
|
||||||
IconBookmarkPlus,
|
IconBookmarkPlus,
|
||||||
|
IconCopy,
|
||||||
IconPencil,
|
IconPencil,
|
||||||
IconTrash,
|
IconTrash,
|
||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
@ -19,9 +20,11 @@ type MultiItemFieldMenuItemProps<T> = {
|
|||||||
onEdit?: () => void;
|
onEdit?: () => void;
|
||||||
onSetAsPrimary?: () => void;
|
onSetAsPrimary?: () => void;
|
||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
|
onCopy?: (value: T) => void;
|
||||||
DisplayComponent: React.ComponentType<{ value: T }>;
|
DisplayComponent: React.ComponentType<{ value: T }>;
|
||||||
showPrimaryIcon: boolean;
|
showPrimaryIcon: boolean;
|
||||||
showSetAsPrimaryButton: boolean;
|
showSetAsPrimaryButton: boolean;
|
||||||
|
showCopyButton?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MultiItemFieldMenuItem = <T,>({
|
export const MultiItemFieldMenuItem = <T,>({
|
||||||
@ -33,6 +36,8 @@ export const MultiItemFieldMenuItem = <T,>({
|
|||||||
DisplayComponent,
|
DisplayComponent,
|
||||||
showPrimaryIcon,
|
showPrimaryIcon,
|
||||||
showSetAsPrimaryButton,
|
showSetAsPrimaryButton,
|
||||||
|
showCopyButton,
|
||||||
|
onCopy,
|
||||||
}: MultiItemFieldMenuItemProps<T>) => {
|
}: MultiItemFieldMenuItemProps<T>) => {
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const { closeDropdown } = useCloseDropdown();
|
const { closeDropdown } = useCloseDropdown();
|
||||||
@ -71,6 +76,14 @@ export const MultiItemFieldMenuItem = <T,>({
|
|||||||
onEdit?.();
|
onEdit?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCopyClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
closeDropdown(dropdownId);
|
||||||
|
onCopy?.(value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuItemWithOptionDropdown
|
<MenuItemWithOptionDropdown
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
@ -100,6 +113,13 @@ export const MultiItemFieldMenuItem = <T,>({
|
|||||||
text="Delete"
|
text="Delete"
|
||||||
onClick={handleDeleteClick}
|
onClick={handleDeleteClick}
|
||||||
/>
|
/>
|
||||||
|
{showCopyButton && (
|
||||||
|
<MenuItem
|
||||||
|
LeftIcon={IconCopy}
|
||||||
|
text="Copy"
|
||||||
|
onClick={handleCopyClick}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownContent>
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFi
|
|||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { EmailsFieldInput } from '../EmailsFieldInput';
|
import { EmailsFieldInput } from '../EmailsFieldInput';
|
||||||
|
|
||||||
const updateRecord = fn();
|
const updateRecord = fn();
|
||||||
@ -113,6 +115,7 @@ const EmailInputWithContext = ({
|
|||||||
const meta: Meta<typeof EmailInputWithContext> = {
|
const meta: Meta<typeof EmailInputWithContext> = {
|
||||||
title: 'UI/Input/EmailsFieldInput',
|
title: 'UI/Input/EmailsFieldInput',
|
||||||
component: EmailInputWithContext,
|
component: EmailInputWithContext,
|
||||||
|
decorators: [SnackBarDecorator, I18nFrontDecorator],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
|||||||
Reference in New Issue
Block a user