Skip to content

Commit 15a72ef

Browse files
committed
Refactor app specific logic in Link into ExternalLink and InternalLink
1 parent 4f1896c commit 15a72ef

File tree

6 files changed

+73
-36
lines changed

6 files changed

+73
-36
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useCallback } from 'react';
2+
3+
import { Url } from '../../shared/constants';
4+
import { useAppContext } from '../context';
5+
import { Link, LinkProps } from '../lib/components';
6+
7+
export type ExternalLinkProps = Omit<LinkProps<'a'>, 'href' | 'as'> & {
8+
to: Url;
9+
};
10+
11+
export const ExternalLink = ({ to, onClick, ...props }: ExternalLinkProps) => {
12+
const { openUrl } = useAppContext();
13+
const navigate = useCallback(
14+
(e: React.MouseEvent<HTMLAnchorElement>) => {
15+
e.preventDefault();
16+
if (onClick) {
17+
onClick(e);
18+
}
19+
return openUrl(to);
20+
},
21+
[onClick, openUrl, to],
22+
);
23+
return <Link href="" onClick={navigate} {...props} />;
24+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useCallback } from 'react';
2+
3+
import { Link, LinkProps } from '../lib/components';
4+
import { useHistory } from '../lib/history';
5+
import { RoutePath } from '../lib/routes';
6+
7+
export type InternalLinkProps = Omit<LinkProps<'a'>, 'href' | 'as'> & {
8+
to: RoutePath;
9+
};
10+
11+
export const InternalLink = ({ to, onClick, ...props }: InternalLinkProps) => {
12+
const history = useHistory();
13+
const navigate = useCallback(
14+
(e: React.MouseEvent<HTMLAnchorElement>) => {
15+
e.preventDefault();
16+
if (onClick) {
17+
onClick(e);
18+
}
19+
return history.push(to);
20+
},
21+
[history, to, onClick],
22+
);
23+
return <Link href="" onClick={navigate} {...props} />;
24+
};

desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
} from '../../shared/notifications';
1717
import { useAppContext } from '../context';
1818
import useActions from '../lib/actionsHook';
19-
import { Link } from '../lib/components';
2019
import { Colors } from '../lib/foundations';
2120
import { transitions, useHistory } from '../lib/history';
2221
import { formatHtml } from '../lib/html-formatter';
@@ -28,6 +27,7 @@ import { RoutePath } from '../lib/routes';
2827
import accountActions from '../redux/account/actions';
2928
import { IReduxState, useSelector } from '../redux/store';
3029
import * as AppButton from './AppButton';
30+
import { InternalLink } from './InternalLink';
3131
import { ModalAlert, ModalAlertType, ModalMessage, ModalMessageList } from './Modal';
3232
import {
3333
NotificationActions,
@@ -141,13 +141,13 @@ export default function NotificationArea(props: IProps) {
141141
{notification.title}
142142
</NotificationTitle>
143143
<NotificationSubtitle data-testid="notificationSubTitle">
144-
{notification.subtitleAction?.type === 'navigate' ? (
145-
<Link
144+
{notification.subtitleAction?.type === 'navigate-internal' ? (
145+
<InternalLink
146146
variant="labelTiny"
147147
color={Colors.white60}
148148
{...notification.subtitleAction.link}>
149149
{formatHtml(notification.subtitle ?? '')}
150-
</Link>
150+
</InternalLink>
151151
) : (
152152
formatHtml(notification.subtitle ?? '')
153153
)}

desktop/packages/mullvad-vpn/src/renderer/lib/components/typography/Link.tsx

+17-28
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
1-
import React, { useCallback } from 'react';
21
import styled from 'styled-components';
2+
import { KnownTarget } from 'styled-components/dist/types';
33

44
import { Colors, Radius } from '../../foundations';
5-
import { useHistory } from '../../history';
6-
import { RoutePath } from '../../routes';
7-
import { buttonReset } from '../../styles';
85
import { Text, TextProps } from './Text';
96

10-
export interface LinkProps extends Omit<TextProps<'button'>, 'color'> {
11-
to: RoutePath;
12-
color?: Colors;
13-
}
7+
export type LinkProps<T extends KnownTarget = 'a'> = TextProps<T> & {
8+
onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;
9+
};
1410

1511
const StyledText = styled(Text)<{
1612
$hoverColor: Colors | undefined;
1713
}>((props) => ({
18-
...buttonReset,
1914
background: 'transparent',
15+
cursor: 'default',
16+
textDecoration: 'none',
17+
display: 'inline-flex',
18+
width: 'fit-content',
2019

21-
'&:hover': {
20+
'&&:hover': {
2221
textDecorationLine: 'underline',
2322
textUnderlineOffset: '2px',
2423
color: props.$hoverColor,
2524
},
26-
'&:focus-visible': {
25+
'&&:focus-visible': {
2726
borderRadius: Radius.radius4,
2827
outline: `2px solid ${Colors.white}`,
2928
outlineOffset: '2px',
@@ -39,24 +38,14 @@ const getHoverColor = (color: Colors | undefined) => {
3938
}
4039
};
4140

42-
export const Link = ({ to, children, color, onClick, ...props }: LinkProps) => {
43-
const history = useHistory();
44-
const navigate = useCallback(
45-
(e: React.MouseEvent<HTMLButtonElement>) => {
46-
if (onClick) {
47-
onClick(e);
48-
}
49-
return history.push(to);
50-
},
51-
[history, to, onClick],
52-
);
41+
export const Link = <T extends KnownTarget = 'a'>({
42+
as = 'a' as T,
43+
children,
44+
color,
45+
...props
46+
}: LinkProps<T>) => {
5347
return (
54-
<StyledText
55-
onClick={navigate}
56-
as={'button'}
57-
color={color}
58-
$hoverColor={getHoverColor(color)}
59-
{...props}>
48+
<StyledText forwardedAs={as} color={color} $hoverColor={getHoverColor(color)} {...props}>
6049
{children}
6150
</StyledText>
6251
);

desktop/packages/mullvad-vpn/src/renderer/lib/notifications/new-version.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class NewVersionNotificationProvider implements InAppNotificationProvider
2929
title,
3030
subtitle,
3131
subtitleAction: {
32-
type: 'navigate',
32+
type: 'navigate-internal',
3333
link: {
3434
to: RoutePath.changelog,
3535
onClick: this.context.close,

desktop/packages/mullvad-vpn/src/shared/notifications/notification.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { LinkProps } from '../../renderer/lib/components';
1+
import { InternalLinkProps } from '../../renderer/components/InternalLink';
22
import { Url } from '../constants';
33

44
export type NotificationAction = {
@@ -31,8 +31,8 @@ export type InAppNotificationAction =
3131
close: () => void;
3232
}
3333
| {
34-
type: 'navigate';
35-
link: Pick<LinkProps, 'to' | 'onClick' | 'aria-label'>;
34+
type: 'navigate-internal';
35+
link: Pick<InternalLinkProps, 'to' | 'onClick' | 'aria-label'>;
3636
};
3737

3838
export type InAppNotificationIndicatorType = 'success' | 'warning' | 'error';

0 commit comments

Comments
 (0)