fix: Fixed LinkedIn links with unicode (#3953)
* fix: Fixed LinkedIn links with unicode * feat: Added checkUrlType and getDisplayValueByUrlType util functions
This commit is contained in:
@ -7,6 +7,7 @@ import {
|
|||||||
LinkType,
|
LinkType,
|
||||||
SocialLink,
|
SocialLink,
|
||||||
} from '@/ui/navigation/link/components/SocialLink';
|
} from '@/ui/navigation/link/components/SocialLink';
|
||||||
|
import { checkUrlType } from '~/utils/checkUrlType';
|
||||||
|
|
||||||
import { EllipsisDisplay } from './EllipsisDisplay';
|
import { EllipsisDisplay } from './EllipsisDisplay';
|
||||||
|
|
||||||
@ -24,21 +25,6 @@ type LinkDisplayProps = {
|
|||||||
value?: FieldLinkValue;
|
value?: FieldLinkValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkUrlType = (url: string) => {
|
|
||||||
if (
|
|
||||||
/^(http|https):\/\/(?:www\.)?linkedin.com(\w+:{0,1}\w*@)?(\S+)(:([0-9])+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(
|
|
||||||
url,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return LinkType.LinkedIn;
|
|
||||||
}
|
|
||||||
if (url.match(/^((http|https):\/\/)?(?:www\.)?twitter\.com\/(\w+)?/i)) {
|
|
||||||
return LinkType.Twitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LinkType.Url;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const LinkDisplay = ({ value }: LinkDisplayProps) => {
|
export const LinkDisplay = ({ value }: LinkDisplayProps) => {
|
||||||
const handleClick = (event: MouseEvent<HTMLElement>) => {
|
const handleClick = (event: MouseEvent<HTMLElement>) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
LinkType,
|
LinkType,
|
||||||
SocialLink,
|
SocialLink,
|
||||||
} from '@/ui/navigation/link/components/SocialLink';
|
} from '@/ui/navigation/link/components/SocialLink';
|
||||||
|
import { checkUrlType } from '~/utils/checkUrlType';
|
||||||
|
|
||||||
import { EllipsisDisplay } from './EllipsisDisplay';
|
import { EllipsisDisplay } from './EllipsisDisplay';
|
||||||
|
|
||||||
@ -23,21 +24,6 @@ type URLDisplayProps = {
|
|||||||
value: string | null;
|
value: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkUrlType = (url: string) => {
|
|
||||||
if (
|
|
||||||
/^(http|https):\/\/(?:www\.)?linkedin.com(\w+:{0,1}\w*@)?(\S+)(:([0-9])+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(
|
|
||||||
url,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return LinkType.LinkedIn;
|
|
||||||
}
|
|
||||||
if (url.match(/^((http|https):\/\/)?(?:www\.)?twitter\.com\/(\w+)?/i)) {
|
|
||||||
return LinkType.Twitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LinkType.Url;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const URLDisplay = ({ value }: URLDisplayProps) => {
|
export const URLDisplay = ({ value }: URLDisplayProps) => {
|
||||||
const handleClick = (event: MouseEvent<HTMLElement>) => {
|
const handleClick = (event: MouseEvent<HTMLElement>) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { getDisplayValueByUrlType } from '~/utils/getDisplayValueByUrlType';
|
||||||
|
|
||||||
import { RoundedLink } from './RoundedLink';
|
import { RoundedLink } from './RoundedLink';
|
||||||
|
|
||||||
export enum LinkType {
|
export enum LinkType {
|
||||||
@ -12,7 +14,7 @@ export enum LinkType {
|
|||||||
type SocialLinkProps = {
|
type SocialLinkProps = {
|
||||||
href: string;
|
href: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
type?: LinkType;
|
type: LinkType;
|
||||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,29 +34,8 @@ export const SocialLink = ({
|
|||||||
onClick,
|
onClick,
|
||||||
type,
|
type,
|
||||||
}: SocialLinkProps) => {
|
}: SocialLinkProps) => {
|
||||||
let displayValue = children;
|
const displayValue =
|
||||||
|
getDisplayValueByUrlType({ type: type, href: href }) ?? children;
|
||||||
if (type === 'linkedin') {
|
|
||||||
const matches = href.match(
|
|
||||||
/(?:https?:\/\/)?(?:www.)?linkedin.com\/(?:in|company)\/([-a-zA-Z0-9@:%_+.~#?&//=]*)/,
|
|
||||||
);
|
|
||||||
if (matches && matches[1]) {
|
|
||||||
displayValue = matches[1];
|
|
||||||
} else {
|
|
||||||
displayValue = 'LinkedIn';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === 'twitter') {
|
|
||||||
const matches = href.match(
|
|
||||||
/(?:https?:\/\/)?(?:www.)?twitter.com\/([-a-zA-Z0-9@:%_+.~#?&//=]*)/,
|
|
||||||
);
|
|
||||||
if (matches && matches[1]) {
|
|
||||||
displayValue = `@${matches[1]}`;
|
|
||||||
} else {
|
|
||||||
displayValue = '@twitter';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledRawLink href={href} onClick={onClick}>
|
<StyledRawLink href={href} onClick={onClick}>
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { checkUrlType } from '~/utils/checkUrlType';
|
||||||
|
|
||||||
|
describe('checkUrlType', () => {
|
||||||
|
it('should return "linkedin", if linkedin url', () => {
|
||||||
|
expect(checkUrlType('https://www.linkedin.com/in/håkan-fisk')).toBe(
|
||||||
|
'linkedin',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return "twitter", if twitter url', () => {
|
||||||
|
expect(checkUrlType('https://www.twitter.com/john-doe')).toBe('twitter');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return "url", if neither linkedin nor twitter url', () => {
|
||||||
|
expect(checkUrlType('https://www.example.com')).toBe('url');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { LinkType } from '@/ui/navigation/link/components/SocialLink';
|
||||||
|
import { getDisplayValueByUrlType } from '~/utils/getDisplayValueByUrlType';
|
||||||
|
|
||||||
|
describe('getDisplayValueByUrlType', () => {
|
||||||
|
it('should return the linkedin username from the url', () => {
|
||||||
|
expect(
|
||||||
|
getDisplayValueByUrlType({
|
||||||
|
type: LinkType.LinkedIn,
|
||||||
|
href: 'https://www.linkedin.com/in/håkan-fisk',
|
||||||
|
}),
|
||||||
|
).toBe('håkan-fisk');
|
||||||
|
expect(
|
||||||
|
getDisplayValueByUrlType({
|
||||||
|
type: LinkType.LinkedIn,
|
||||||
|
href: 'https://www.linkedin.com/in/Matías',
|
||||||
|
}),
|
||||||
|
).toBe('Matías');
|
||||||
|
expect(
|
||||||
|
getDisplayValueByUrlType({
|
||||||
|
type: LinkType.LinkedIn,
|
||||||
|
href: 'https://www.linkedin.com/in/Mårten',
|
||||||
|
}),
|
||||||
|
).toBe('Mårten');
|
||||||
|
expect(
|
||||||
|
getDisplayValueByUrlType({
|
||||||
|
type: LinkType.LinkedIn,
|
||||||
|
href: 'https://www.linkedin.com/in/Sörvik',
|
||||||
|
}),
|
||||||
|
).toBe('Sörvik');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the twitter username from the url', () => {
|
||||||
|
expect(
|
||||||
|
getDisplayValueByUrlType({
|
||||||
|
type: LinkType.Twitter,
|
||||||
|
href: 'https://www.twitter.com/john-doe',
|
||||||
|
}),
|
||||||
|
).toBe('@john-doe');
|
||||||
|
});
|
||||||
|
});
|
||||||
16
packages/twenty-front/src/utils/checkUrlType.ts
Normal file
16
packages/twenty-front/src/utils/checkUrlType.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { LinkType } from '@/ui/navigation/link/components/SocialLink';
|
||||||
|
|
||||||
|
export const checkUrlType = (url: string) => {
|
||||||
|
if (
|
||||||
|
/^(http|https):\/\/(?:www\.)?linkedin.com(\w+:{0,1}\w*@)?(\S+)(:([0-9])+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return LinkType.LinkedIn;
|
||||||
|
}
|
||||||
|
if (url.match(/^((http|https):\/\/)?(?:www\.)?twitter\.com\/(\w+)?/i)) {
|
||||||
|
return LinkType.Twitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LinkType.Url;
|
||||||
|
};
|
||||||
33
packages/twenty-front/src/utils/getDisplayValueByUrlType.ts
Normal file
33
packages/twenty-front/src/utils/getDisplayValueByUrlType.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { LinkType } from '@/ui/navigation/link/components/SocialLink';
|
||||||
|
|
||||||
|
type getUrlDisplayValueByUrlTypeProps = {
|
||||||
|
type: LinkType;
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getDisplayValueByUrlType = ({
|
||||||
|
type,
|
||||||
|
href,
|
||||||
|
}: getUrlDisplayValueByUrlTypeProps) => {
|
||||||
|
if (type === 'linkedin') {
|
||||||
|
const matches = href.match(
|
||||||
|
/(?:https?:\/\/)?(?:www.)?linkedin.com\/(?:in|company)\/(.*)/,
|
||||||
|
);
|
||||||
|
if (matches && matches[1]) {
|
||||||
|
return matches[1];
|
||||||
|
} else {
|
||||||
|
return 'LinkedIn';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'twitter') {
|
||||||
|
const matches = href.match(
|
||||||
|
/(?:https?:\/\/)?(?:www.)?twitter.com\/([-a-zA-Z0-9@:%_+.~#?&//=]*)/,
|
||||||
|
);
|
||||||
|
if (matches && matches[1]) {
|
||||||
|
return `@${matches[1]}`;
|
||||||
|
} else {
|
||||||
|
return '@twitter';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user