From c5ac435f53ea65fe4856113ff130bfbc3f1052cf Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 10 Feb 2023 16:21:01 +0000 Subject: [PATCH] Adjust account urls second attempt after fist caused issues and had to be reverted --- frontend/src/components/Status/index.tsx | 11 +++-- frontend/src/components/avatar/index.tsx | 10 ++-- .../[accountId]/[statusId]/index.tsx | 3 +- frontend/src/utils/useAccountUrl.ts | 46 +++++++++++++++++++ frontend/src/utils/useDomain.ts | 4 +- ui-e2e-tests/account-page.spec.ts | 43 +++++++++-------- 6 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 frontend/src/utils/useAccountUrl.ts diff --git a/frontend/src/components/Status/index.tsx b/frontend/src/components/Status/index.tsx index 0396722..9ebe75c 100644 --- a/frontend/src/components/Status/index.tsx +++ b/frontend/src/components/Status/index.tsx @@ -5,6 +5,7 @@ import { Avatar } from '../avatar' import type { Account, MastodonStatus } from '~/types' import styles from '../../utils/innerHtmlContent.scss?inline' import { MediaGallery } from '../MediaGallery.tsx' +import { useAccountUrl } from '~/utils/useAccountUrl' type Props = { status: MastodonStatus @@ -17,7 +18,7 @@ export default component$((props: Props) => { const status = props.status.reblog ?? props.status const reblogger = props.status.reblog && props.status.account - const accountUrl = `/@${status.account.username}` + const accountUrl = useAccountUrl(status.account) const statusUrl = `${accountUrl}/${status.id}` const handleContentClick = $(() => nav(statusUrl)) @@ -65,13 +66,15 @@ export default component$((props: Props) => { ) }) -export const RebloggerLink = ({ account }: { account: Account | null }) => { +export const RebloggerLink = component$(({ account }: { account: Account | null }) => { + const accountUrl = useAccountUrl(account) + return ( account && (

- + {account.display_name}  boosted @@ -79,4 +82,4 @@ export const RebloggerLink = ({ account }: { account: Account | null }) => {

) ) -} +}) diff --git a/frontend/src/components/avatar/index.tsx b/frontend/src/components/avatar/index.tsx index 9c6e15a..6611c0d 100644 --- a/frontend/src/components/avatar/index.tsx +++ b/frontend/src/components/avatar/index.tsx @@ -1,7 +1,8 @@ import { component$ } from '@builder.io/qwik' import type { Account } from '~/types' +import { useAccountUrl } from '~/utils/useAccountUrl' -type AvatarDetails = Pick +type AvatarDetails = Partial> & Pick type Props = { primary: AvatarDetails @@ -9,13 +10,16 @@ type Props = { } export const Avatar = component$(({ primary, secondary }) => { + const primaryUrl = useAccountUrl(primary) + const secondaryUrl = useAccountUrl(secondary) + return (
- + {`Avatar {secondary && ( - + { }) export const AccountCard = component$<{ status: MastodonStatus }>(({ status }) => { - const accountUrl = `/@${status.account.username}` + const accountUrl = useAccountUrl(status.account) return (
diff --git a/frontend/src/utils/useAccountUrl.ts b/frontend/src/utils/useAccountUrl.ts new file mode 100644 index 0000000..44627d5 --- /dev/null +++ b/frontend/src/utils/useAccountUrl.ts @@ -0,0 +1,46 @@ +import { useSignal, useTask$ } from '@builder.io/qwik' +import { parseHandle } from 'wildebeest/backend/src/utils/parse' +import { Account } from '~/types' +import { useDomain } from './useDomain' + +/** + * Hook to get a url to use for links for the provided account. + * + * Note: using account.url is not sufficient since we want to distinguish + * between local and remote accounts and change the url accordingly + * + * @param account the target account or null + * @returns url to be used for the target account (or undefined if) + */ +export function useAccountUrl( + account: (Partial> & Pick) | null +): string | undefined { + if (!account?.id) { + return account?.url + } + + const isLocal = useAccountIsLocal(account?.id) + + if (account && isLocal.value) { + const url = new URL(account.url) + return url.pathname + } + + return account?.url +} + +function useAccountIsLocal(accountId: string | undefined) { + const domain = useDomain() + const isLocal = useSignal(false) + + useTask$(({ track }) => { + track(() => accountId) + + if (accountId) { + const handle = parseHandle(accountId) + isLocal.value = handle.domain === null || handle.domain === domain + } + }) + + return isLocal +} diff --git a/frontend/src/utils/useDomain.ts b/frontend/src/utils/useDomain.ts index 769c465..98bbe5e 100644 --- a/frontend/src/utils/useDomain.ts +++ b/frontend/src/utils/useDomain.ts @@ -1,8 +1,10 @@ import { useLocation } from '@builder.io/qwik-city' +import { adjustLocalHostDomain } from 'wildebeest/backend/src/utils/adjustLocalHostDomain' export const useDomain = () => { const location = useLocation() const url = new URL(location.href) const domain = url.hostname - return domain + const adjustedDomain = adjustLocalHostDomain(domain) + return adjustedDomain } diff --git a/ui-e2e-tests/account-page.spec.ts b/ui-e2e-tests/account-page.spec.ts index 77cd122..ea5ea70 100644 --- a/ui-e2e-tests/account-page.spec.ts +++ b/ui-e2e-tests/account-page.spec.ts @@ -1,26 +1,31 @@ import { test, expect } from '@playwright/test' -test('Navigation to and view of an account (with 1 post)', async ({ page }) => { - await page.goto('http://127.0.0.1:8788/explore') - await page.getByRole('article').getByRole('link', { name: 'Ben, just Ben', exact: true }).click() - await page.getByRole('link', { name: 'Ben, just Ben', exact: true }).click() - await page.waitForLoadState('networkidle') - await page.getByRole('link', { name: 'Ben, just Ben', exact: true }).click() +const navigationsVia = ['name link', 'avatar'] as const - await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Ben, just Ben' })).toBeVisible() - await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Ben, just Ben' })).toBeVisible() - await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Ben, just Ben' })).toBeVisible() - await expect(page.getByTestId('account-info').getByText('Joined')).toBeVisible() - await expect(page.getByTestId('account-info').getByTestId('stats')).toHaveText('1Posts0Following0Followers') +navigationsVia.forEach((via) => + test(`Navigation via ${via} to and view of an account (with 1 post)`, async ({ page }) => { + await page.goto('http://127.0.0.1:8788/explore') + await page.getByRole('article').getByRole('link', { name: 'Ben, just Ben', exact: true }).click() + await page.getByRole('link', { name: 'Ben, just Ben', exact: true }).click() + await page.waitForLoadState('networkidle') + const linkOption = + via === 'name link' ? { name: 'Ben, just Ben', exact: true } : { name: 'Avatar of Ben, just Ben' } + await page.getByRole('link', linkOption).click() + await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Ben, just Ben' })).toBeVisible() + await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Ben, just Ben' })).toBeVisible() + await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Ben, just Ben' })).toBeVisible() + await expect(page.getByTestId('account-info').getByText('Joined')).toBeVisible() + await expect(page.getByTestId('account-info').getByTestId('stats')).toHaveText('1Posts0Following0Followers') - expect(await page.getByTestId('account-statuses').getByRole('article').count()).toBe(1) - await expect( - page.getByTestId('account-statuses').getByRole('article').getByRole('img', { name: 'Avatar of Ben, just Ben' }) - ).toBeVisible() - await expect(page.getByTestId('account-statuses').getByRole('article')).toContainText( - 'A very simple update: all good!' - ) -}) + expect(await page.getByTestId('account-statuses').getByRole('article').count()).toBe(1) + await expect( + page.getByTestId('account-statuses').getByRole('article').getByRole('img', { name: 'Avatar of Ben, just Ben' }) + ).toBeVisible() + await expect(page.getByTestId('account-statuses').getByRole('article')).toContainText( + 'A very simple update: all good!' + ) + }) +) test('Navigation to and view of an account (with 2 posts)', async ({ page }) => { await page.goto('http://127.0.0.1:8788/explore')