Skip to content

Commit

Permalink
Clicking a phone number should copy its value (#9069)
Browse files Browse the repository at this point in the history
https://github.com/user-attachments/assets/7ce595fa-be90-4ec7-81e5-075dafee6422

I have added the functionality of copying the phone number to clipboard
according to the issue #8905 . If anything needed to change just comment
in my PR

---------

Co-authored-by: Lucas Bordeau <[email protected]>
  • Loading branch information
Lucifer4255 and lucasbordeau authored Dec 30, 2024
1 parent c52a492 commit 578ba97
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,50 @@
import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus';
import { usePhonesFieldDisplay } from '@/object-record/record-field/meta-types/hooks/usePhonesFieldDisplay';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { PhonesDisplay } from '@/ui/field/display/components/PhonesDisplay';
import React from 'react';
import { useIcons } from 'twenty-ui';

export const PhonesFieldDisplay = () => {
const { fieldValue } = usePhonesFieldDisplay();

const { isFocused } = useFieldFocus();

return <PhonesDisplay value={fieldValue} isFocused={isFocused} />;
const { enqueueSnackBar } = useSnackBar();

const { getIcon } = useIcons();

const IconCircleCheck = getIcon('IconCircleCheck');
const IconExclamationCircle = getIcon('IconExclamationCircle');

const handleClick = async (
phoneNumber: string,
event: React.MouseEvent<HTMLElement>,
) => {
event.preventDefault();

try {
await navigator.clipboard.writeText(phoneNumber);
enqueueSnackBar('Phone number copied to clipboard', {
variant: SnackBarVariant.Success,
icon: <IconCircleCheck size={16} color="green" />,
duration: 2000,
});
} catch (err) {
enqueueSnackBar('Error copying to clipboard', {
variant: SnackBarVariant.Error,
icon: <IconExclamationCircle size={16} color="red" />,
duration: 2000,
});
}
};

return (
<PhonesDisplay
value={fieldValue}
isFocused={isFocused}
onPhoneNumberClick={handleClick}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ComponentDecorator } from 'twenty-ui';
import { PhonesFieldDisplay } from '@/object-record/record-field/meta-types/display/components/PhonesFieldDisplay';
import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator';
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';

const meta: Meta = {
Expand All @@ -12,6 +13,7 @@ const meta: Meta = {
MemoryRouterDecorator,
getFieldDecorator('person', 'phones'),
ComponentDecorator,
SnackBarDecorator,
],
component: PhonesFieldDisplay,
args: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ const StyledHeader = styled.div`
font-weight: ${({ theme }) => theme.font.weight.medium};
gap: ${({ theme }) => theme.spacing(2)};
height: ${({ theme }) => theme.spacing(6)};
margin-bottom: ${({ theme }) => theme.spacing(1)};
`;

const StyledActions = styled.div`
Expand All @@ -83,15 +82,6 @@ const StyledActions = styled.div`
margin-left: auto;
`;

const StyledDescription = styled.div`
color: ${({ theme }) => theme.font.color.tertiary};
font-size: ${({ theme }) => theme.font.size.sm};
padding-left: ${({ theme }) => theme.spacing(6)};
overflow: hidden;
text-overflow: ellipsis;
width: 200px;
`;

const defaultTitleByVariant: Record<SnackBarVariant, string> = {
[SnackBarVariant.Default]: 'Alert',
[SnackBarVariant.Error]: 'Error',
Expand Down Expand Up @@ -183,7 +173,7 @@ export const SnackBar = ({
/>
<StyledHeader>
{icon}
{title}
{message}
<StyledActions>
{!!onCancel && <LightButton title="Cancel" onClick={onCancel} />}

Expand All @@ -192,7 +182,6 @@ export const SnackBar = ({
)}
</StyledActions>
</StyledHeader>
{message && <StyledDescription>{message}</StyledDescription>}
</StyledContainer>
);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from '@emotion/styled';
import { useMemo } from 'react';
import React, { useMemo } from 'react';
import { RoundedLink, THEME_COMMON } from 'twenty-ui';

import { FieldPhonesValue } from '@/object-record/record-field/types/FieldMetadata';
Expand All @@ -13,6 +13,10 @@ import { logError } from '~/utils/logError';
type PhonesDisplayProps = {
value?: FieldPhonesValue;
isFocused?: boolean;
onPhoneNumberClick?: (
phoneNumber: string,
event: React.MouseEvent<HTMLElement>,
) => void;
};

const themeSpacing = THEME_COMMON.spacingMultiplicator;
Expand All @@ -30,7 +34,11 @@ const StyledContainer = styled.div`
width: 100%;
`;

export const PhonesDisplay = ({ value, isFocused }: PhonesDisplayProps) => {
export const PhonesDisplay = ({
value,
isFocused,
onPhoneNumberClick,
}: PhonesDisplayProps) => {
const phones = useMemo(
() =>
[
Expand Down Expand Up @@ -67,6 +75,13 @@ export const PhonesDisplay = ({ value, isFocused }: PhonesDisplayProps) => {
}
};

const handleClick = (
number: string,
event: React.MouseEvent<HTMLElement>,
) => {
onPhoneNumberClick?.(number, event);
};

return isFocused ? (
<ExpandableList isChipCountDisplayed>
{phones.map(({ number, callingCode }, index) => {
Expand All @@ -80,6 +95,7 @@ export const PhonesDisplay = ({ value, isFocused }: PhonesDisplayProps) => {
label={
parsedPhone ? parsedPhone.formatInternational() : invalidPhone
}
onClick={(event) => handleClick(callingCode + number, event)}
/>
);
})}
Expand All @@ -97,6 +113,7 @@ export const PhonesDisplay = ({ value, isFocused }: PhonesDisplayProps) => {
label={
parsedPhone ? parsedPhone.formatInternational() : invalidPhone
}
onClick={(event) => handleClick(callingCode + number, event)}
/>
);
})}
Expand Down

0 comments on commit 578ba97

Please sign in to comment.