Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clicking a phone number should copy its value #9069

Merged
merged 6 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading