diff --git a/packages/webapp/__tests__/SquadFeedPage.tsx b/packages/webapp/__tests__/SquadFeedPage.tsx index 48caca498a..c9d07d015a 100644 --- a/packages/webapp/__tests__/SquadFeedPage.tsx +++ b/packages/webapp/__tests__/SquadFeedPage.tsx @@ -44,6 +44,7 @@ import { } from '@dailydotdev/shared/src/graphql/squads'; import { type SourceMember, + SourceType, type Squad, SourceMemberRole, SourcePermissions, @@ -57,8 +58,9 @@ import { CONTENT_PREFERENCE_STATUS_QUERY, ContentPreferenceType, } from '@dailydotdev/shared/src/graphql/contentPreference'; +import { gqlClient } from '@dailydotdev/shared/src/graphql/common'; import { useSquad } from '@dailydotdev/shared/src/hooks/squads/useSquad'; -import SquadPage from '../pages/squads/[handle]'; +import SquadPage, { getServerSideProps } from '../pages/squads/[handle]'; const defaultSquad: Squad = { ...generateTestSquad(), @@ -259,6 +261,35 @@ const renderComponent = ( }; describe('squad page', () => { + it('should redirect machine sources to the canonical sources route', async () => { + jest.spyOn(gqlClient, 'request').mockResolvedValueOnce({ + source: { + id: 'daily', + name: 'daily.dev', + image: 'https://daily.dev/daily.png', + handle: 'daily', + permalink: 'https://app.daily.dev/sources/daily', + type: SourceType.Machine, + public: true, + }, + } as Awaited>); + + const setHeader = jest.fn(); + const result = await getServerSideProps({ + params: { handle: 'daily' }, + query: {}, + res: { setHeader }, + } as never); + + expect(setHeader).toHaveBeenCalled(); + expect(result).toEqual({ + redirect: { + destination: '/sources/daily', + permanent: false, + }, + }); + }); + it('should request source feed', async () => { renderComponent(); await waitForNock(); diff --git a/packages/webapp/pages/squads/[handle]/index.tsx b/packages/webapp/pages/squads/[handle]/index.tsx index 79493bb513..4a8cdeb092 100644 --- a/packages/webapp/pages/squads/[handle]/index.tsx +++ b/packages/webapp/pages/squads/[handle]/index.tsx @@ -26,8 +26,14 @@ import { } from '@dailydotdev/shared/src/graphql/squads'; import type { BasicSourceMember, + SourceData, Squad, } from '@dailydotdev/shared/src/graphql/sources'; +import { + isSourceUserSource, + SOURCE_QUERY, + SourceType, +} from '@dailydotdev/shared/src/graphql/sources'; import Unauthorized from '@dailydotdev/shared/src/components/errors/Unauthorized'; import { useQuery } from '@tanstack/react-query'; import { @@ -496,6 +502,32 @@ export async function getServerSideProps({ }; try { + const sourceResult = await gqlClient.request(SOURCE_QUERY, { + id: handle, + }); + + if (isSourceUserSource(sourceResult.source)) { + setCacheHeader(); + + return { + redirect: { + destination: `/${sourceResult.source.id}`, + permanent: false, + }, + }; + } + + if (sourceResult.source?.type === SourceType.Machine) { + setCacheHeader(); + + return { + redirect: { + destination: `/sources/${handle}`, + permanent: false, + }, + }; + } + const referringUserPromise = userId && campaign ? gqlClient @@ -553,8 +585,9 @@ export async function getServerSideProps({ } catch (err) { const clientError = err as ClientError; const errors = Object.values(ApiError); + const errorCode = clientError?.response?.errors?.[0]?.extensions?.code; - if (errors.includes(clientError?.response?.errors?.[0]?.extensions?.code)) { + if (errors.includes(errorCode)) { setCacheHeader(); return {