From 4ae7dcec31212aa64feaa4241467e802a7570eb3 Mon Sep 17 00:00:00 2001 From: katspaugh <381895+katspaugh@users.noreply.github.com> Date: Mon, 17 Apr 2023 15:55:20 +0300 Subject: [PATCH] Fix: redirect old tx id URLs (#1870) * Fix: redirect old tx id URLs * Update src/pages/404.tsx Co-authored-by: Aaron Cook * Bump the version --------- Co-authored-by: Aaron Cook --- package.json | 2 +- .../transactions/TxShareLink/index.tsx | 2 +- src/pages/404.tsx | 24 +++++++--- src/tests/pages/404.test.tsx | 46 +++++++++++++++++++ 4 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 src/tests/pages/404.test.tsx diff --git a/package.json b/package.json index 676801acea..3a383200a4 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "homepage": "https://github.com/safe-global/web-core", "license": "GPL-3.0", "type": "module", - "version": "1.8.0", + "version": "1.8.1", "scripts": { "dev": "next dev", "start": "next dev", diff --git a/src/components/transactions/TxShareLink/index.tsx b/src/components/transactions/TxShareLink/index.tsx index 536415d128..7a1a28a7f8 100644 --- a/src/components/transactions/TxShareLink/index.tsx +++ b/src/components/transactions/TxShareLink/index.tsx @@ -9,7 +9,7 @@ import { TX_LIST_EVENTS } from '@/services/analytics/events/txList' const TxShareLink = ({ id }: { id: string }): ReactElement => { const router = useRouter() const { safe = '' } = router.query - const href = `/${safe}${AppRoutes.transactions.tx}?id=${id}` + const href = `${AppRoutes.transactions.tx}?safe=${safe}&id=${id}` const onClick = (e: MouseEvent) => { if (!e.ctrlKey && !e.metaKey) { diff --git a/src/pages/404.tsx b/src/pages/404.tsx index a51c91550f..60ee9e69b7 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,20 +1,30 @@ import { useEffect, useState } from 'react' import type { NextPage } from 'next' import { useRouter } from 'next/router' +import { AppRoutes } from '@/config/routes' // Rewrite the URL to put the Safe address into the query. -const getRedirectUrl = (): string | undefined => { - if (typeof location === 'undefined') return - +export const _getRedirectUrl = (location: Location): string | undefined => { const { pathname, search } = location const re = /^\/([^/]+?:0x[0-9a-f]{40})/i const [, pathSafe] = pathname.match(re) || [] if (pathSafe) { - const newPath = pathname.replace(re, '') || '/' + let newPath = pathname.replace(re, '') || '/' + let newSearch = search ? '&' + search.slice(1) : '' + + // TxId used to be in the path, rewrite it to the query + if (newPath.startsWith(AppRoutes.transactions.index)) { + const isStaticPath = Object.values(AppRoutes.transactions).some((route) => route === newPath) + if (!isStaticPath) { + const txId = newPath.match(/\/transactions\/([^/]+)/)?.[1] + newPath = AppRoutes.transactions.tx + newSearch = `${newSearch}&id=${txId}` + } + } if (newPath !== pathname) { - return `${newPath}?safe=${pathSafe}${search ? '&' + search.slice(1) : ''}` + return `${newPath}?safe=${pathSafe}${newSearch}` } } } @@ -24,7 +34,9 @@ const Custom404: NextPage = () => { const [isRedirecting, setIsRedirecting] = useState(true) useEffect(() => { - const redirectUrl = getRedirectUrl() + if (typeof location === 'undefined') return + + const redirectUrl = _getRedirectUrl(location) if (redirectUrl) { router.replace(redirectUrl) diff --git a/src/tests/pages/404.test.tsx b/src/tests/pages/404.test.tsx new file mode 100644 index 0000000000..dd5425082e --- /dev/null +++ b/src/tests/pages/404.test.tsx @@ -0,0 +1,46 @@ +import { _getRedirectUrl } from '../../pages/404' + +describe('_getRedirectUrl', () => { + it('moves a safe address from the path to the query', () => { + const url = _getRedirectUrl({ + pathname: '/eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6/balances', + search: '', + } as Location) + expect(url).toBe('/balances?safe=eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6') + }) + + it('returns undefined if the path is not a safe address', () => { + const url = _getRedirectUrl({ + pathname: '/welcome', + search: '', + } as Location) + expect(url).toBeUndefined() + }) + + it('preserves query parameters', () => { + const url = _getRedirectUrl({ + pathname: '/eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6/transactions/history', + search: '?foo=bar&baz=qux', + } as Location) + expect(url).toBe('/transactions/history?safe=eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6&foo=bar&baz=qux') + }) + + it('rewrites tx id from path to query', () => { + const url = _getRedirectUrl({ + pathname: + '/eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6/transactions/multisig_0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6_0x102f72ce18d977a144ddef78c1f35a3102d04e94cc39e3e59d874874f22a7ec2', + search: '', + } as Location) + expect(url).toBe( + '/transactions/tx?safe=eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6&id=multisig_0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6_0x102f72ce18d977a144ddef78c1f35a3102d04e94cc39e3e59d874874f22a7ec2', + ) + }) + + it('does not rewrite other transaction routes', () => { + const url = _getRedirectUrl({ + pathname: '/eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6/transactions/messages', + search: '', + } as Location) + expect(url).toBe('/transactions/messages?safe=eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6') + }) +})