Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 3 additions & 177 deletions packages/shared/src/components/quest/QuestButton.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from 'react';
import { useRouter } from 'next/router';
import { QueryClient } from '@tanstack/react-query';
import { act, render, screen, waitFor, within } from '@testing-library/react';
import { act, render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { ReactElement, ReactNode } from 'react';
import { TestBootProvider } from '../../../__tests__/helpers/boot';
import loggedUser from '../../../__tests__/fixture/loggedUser';
import type { QuestDashboard } from '../../graphql/quests';
import {
QuestRewardType,
Expand All @@ -16,7 +15,6 @@ import {
} from '../../graphql/quests';
import { QuestButton } from './QuestButton';
import { useClaimQuestReward } from '../../hooks/useClaimQuestReward';
import { useMarkQuestRotationsViewed } from '../../hooks/useMarkQuestRotationsViewed';
import { useQuestDashboard } from '../../hooks/useQuestDashboard';
import { usePlusSubscription } from '../../hooks/usePlusSubscription';
import useSubscription from '../../hooks/useSubscription';
Expand All @@ -40,10 +38,6 @@ jest.mock('../../hooks/useClaimQuestReward', () => ({
useClaimQuestReward: jest.fn(),
}));

jest.mock('../../hooks/useMarkQuestRotationsViewed', () => ({
useMarkQuestRotationsViewed: jest.fn(),
}));

jest.mock('../icons', () => {
const actual = jest.requireActual('../icons');

Expand Down Expand Up @@ -183,8 +177,6 @@ jest.mock('../tooltip/Tooltip', () => {

const mockUseQuestDashboard = useQuestDashboard as jest.Mock;
const mockUseClaimQuestReward = useClaimQuestReward as jest.Mock;
const mockUseMarkQuestRotationsViewed =
useMarkQuestRotationsViewed as jest.Mock;
const mockUseSubscription = useSubscription as jest.Mock;
const mockUsePlusSubscription = usePlusSubscription as jest.Mock;
const mockLogSubscriptionEvent = jest.fn();
Expand All @@ -199,7 +191,6 @@ const questDashboard = {
},
currentStreak: 0,
longestStreak: 0,
hasNewQuestRotations: false,
daily: {
regular: [
{
Expand Down Expand Up @@ -230,27 +221,25 @@ const questDashboard = {
plus: [],
},
milestone: [],
intro: [],
};

const renderComponent = ({
optOutLevelSystem = false,
client = new QueryClient(),
compact = false,
log = {},
auth = {},
}: {
optOutLevelSystem?: boolean;
client?: QueryClient;
compact?: boolean;
log?: Record<string, unknown>;
auth?: Record<string, unknown>;
} = {}) =>
render(
<TestBootProvider
client={client}
settings={{ optOutLevelSystem }}
log={log}
auth={auth}
>
<QuestButton compact={compact} />
</TestBootProvider>,
Expand All @@ -271,10 +260,6 @@ beforeEach(() => {
isPending: false,
variables: undefined,
});
mockUseMarkQuestRotationsViewed.mockReturnValue({
mutate: jest.fn(),
isPending: false,
});
mockUseSubscription.mockReset();
mockLogSubscriptionEvent.mockReset();
mockUsePlusSubscription.mockReturnValue({
Expand Down Expand Up @@ -621,130 +606,9 @@ describe('QuestButton', () => {
});
});

it('should not show a new indicator when the dashboard reports no new quest rotations', async () => {
it('should never render the new quest indicator bubble', () => {
renderComponent();

expect(
screen.getByRole('button', {
name: /Quests, level 7, 63% progress/i,
}),
).toBeInTheDocument();
expect(
screen.queryByTestId('quest-button-new-indicator'),
).not.toBeInTheDocument();
});

it('should show and clear the new quest indicator after a quest rotation update', async () => {
const client = new QueryClient();
const establishedUser = {
...loggedUser,
createdAt: new Date(Date.now() - 48 * 60 * 60 * 1000).toISOString(),
};
const subscriptions: Array<{
query: string;
next?: () => unknown;
}> = [];
let questDashboardState = {
data: questDashboard,
isPending: false,
isError: false,
dataUpdatedAt: 1,
};
const markQuestRotationsViewed = jest.fn(() => {
questDashboardState = {
...questDashboardState,
data: {
...questDashboardState.data,
hasNewQuestRotations: false,
},
dataUpdatedAt: 3,
};
});

mockUseQuestDashboard.mockImplementation(() => questDashboardState);
mockUseMarkQuestRotationsViewed.mockReturnValue({
mutate: markQuestRotationsViewed,
isPending: false,
});
mockUseSubscription.mockImplementation(
(
request: () => { query: string },
callbacks: { next?: () => unknown },
) => {
subscriptions.push({
query: request().query,
next: callbacks.next,
});
},
);

const view = render(
<TestBootProvider client={client} auth={{ user: establishedUser }}>
<QuestButton />
</TestBootProvider>,
);

questDashboardState = {
data: {
...questDashboard,
hasNewQuestRotations: true,
daily: {
...questDashboard.daily,
regular: [
{
...questDashboard.daily.regular[0],
rotationId: 'daily-quest-2',
},
],
},
},
isPending: false,
isError: false,
dataUpdatedAt: 2,
};

subscriptions
.find(
(subscription) =>
subscription.query === QUEST_ROTATION_UPDATE_SUBSCRIPTION,
)
?.next?.();

view.rerender(
<TestBootProvider client={client} auth={{ user: establishedUser }}>
<QuestButton />
</TestBootProvider>,
);

expect(
screen.getByRole('button', {
name: /Quests, level 7, 63% progress, new quests available/i,
}),
).toBeInTheDocument();
expect(
screen.getByTestId('quest-button-new-indicator'),
).toBeInTheDocument();
expect(screen.getByTestId('quest-button-new-indicator')).toHaveTextContent(
'new',
);
expect(markQuestRotationsViewed).not.toHaveBeenCalled();

await userEvent.click(
screen.getByRole('button', {
name: /Quests, level 7, 63% progress, new quests available/i,
}),
);

await waitFor(() => {
expect(markQuestRotationsViewed).toHaveBeenCalledTimes(1);
});

view.rerender(
<TestBootProvider client={client} auth={{ user: establishedUser }}>
<QuestButton />
</TestBootProvider>,
);

expect(
screen.queryByTestId('quest-button-new-indicator'),
).not.toBeInTheDocument();
Expand Down Expand Up @@ -1514,42 +1378,4 @@ describe('QuestButton', () => {
exact: true,
});
});

it('should not show new indicator for users created less than 24 hours ago', () => {
mockUseQuestDashboard.mockReturnValue({
data: { ...questDashboard, hasNewQuestRotations: true },
isPending: false,
isError: false,
});

const newUser = {
...loggedUser,
createdAt: new Date(Date.now() - 12 * 60 * 60 * 1000).toISOString(),
};

renderComponent({ auth: { user: newUser } });

expect(
screen.queryByTestId('quest-button-new-indicator'),
).not.toBeInTheDocument();
});

it('should show new indicator for users created more than 24 hours ago', () => {
mockUseQuestDashboard.mockReturnValue({
data: { ...questDashboard, hasNewQuestRotations: true },
isPending: false,
isError: false,
});

const establishedUser = {
...loggedUser,
createdAt: new Date(Date.now() - 48 * 60 * 60 * 1000).toISOString(),
};

renderComponent({ auth: { user: establishedUser } });

expect(
screen.getByTestId('quest-button-new-indicator'),
).toBeInTheDocument();
});
});
37 changes: 2 additions & 35 deletions packages/shared/src/components/quest/QuestButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import {
QUEST_UPDATE_SUBSCRIPTION,
} from '../../graphql/quests';
import { useClaimQuestReward } from '../../hooks/useClaimQuestReward';
import { useMarkQuestRotationsViewed } from '../../hooks/useMarkQuestRotationsViewed';
import { useQuestDashboard } from '../../hooks/useQuestDashboard';
import { usePlusSubscription } from '../../hooks/usePlusSubscription';
import { useAuthContext } from '../../contexts/AuthContext';
Expand Down Expand Up @@ -758,7 +757,6 @@ export const QuestButton = ({
const level = data?.level?.level ?? 1;
const levelProgress = data?.level ? getLevelProgress(data.level) : 0;
const showLevelSystem = !optOutLevelSystem;
const { mutate: markQuestRotationsViewed } = useMarkQuestRotationsViewed();
const claimableCount = useMemo(() => {
if (!data) {
return 0;
Expand Down Expand Up @@ -813,11 +811,6 @@ export const QuestButton = ({
const triggerVisualClassName = compact ? 'size-8' : 'size-10';
const triggerLevelClassName = compact ? 'typo-caption2' : 'typo-caption1';
const [isOpen, setIsOpen] = useState(false);
const isAccountOlderThan24Hours =
!!user?.createdAt &&
Date.now() - new Date(user.createdAt).getTime() > 24 * 60 * 60 * 1000;
const hasNewQuestRotations =
(data?.hasNewQuestRotations ?? false) && isAccountOlderThan24Hours;
const claimedStampRotationIdSet = useMemo(
() => new Set(claimedStampRotationIds),
[claimedStampRotationIds],
Expand All @@ -836,14 +829,6 @@ export const QuestButton = ({
);
const scrollFadeRef = useScrollFade<HTMLDivElement>();

useEffect(() => {
if (!isOpen || !hasNewQuestRotations) {
return;
}

markQuestRotationsViewed();
}, [hasNewQuestRotations, isOpen, markQuestRotationsViewed]);

const clearProgressTimers = useCallback(() => {
progressTimersRef.current.forEach((timerId) => {
window.clearTimeout(timerId);
Expand Down Expand Up @@ -1228,12 +1213,8 @@ export const QuestButton = ({
showLevelSystem
? `Quests, level ${renderedLevel}, ${Math.round(
renderedLevelProgress,
)}% progress${
hasNewQuestRotations ? ', new quests available' : ''
}`
: `Quests${
hasNewQuestRotations ? ', new quests available' : ''
}`
)}% progress`
: 'Quests'
}
>
{showLevelSystem ? (
Expand Down Expand Up @@ -1292,20 +1273,6 @@ export const QuestButton = ({
<TourIcon size={compact ? IconSize.Small : IconSize.Large} />
</span>
)}
{hasNewQuestRotations && !claimableCount && (
<Bubble
aria-hidden
data-testid="quest-button-new-indicator"
className={classNames(
'left-0 top-0 !min-h-0 !min-w-0 !py-0.5 px-1.5 !font-bold lowercase typo-caption2',
compact
? '-translate-x-1.5 -translate-y-1'
: '-translate-x-2 -translate-y-1.5',
)}
>
new
</Bubble>
)}
{claimableCount > 0 && (
<Bubble
className={classNames(
Expand Down
27 changes: 0 additions & 27 deletions packages/shared/src/graphql/quests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export interface QuestDashboard {
level: QuestLevel;
currentStreak: number;
longestStreak: number;
hasNewQuestRotations: boolean;
daily: QuestBucket;
weekly: QuestBucket;
milestone: UserQuest[];
Expand All @@ -89,23 +88,6 @@ export interface QuestUpdateData {
questUpdate: QuestUpdate;
}

export interface QuestRotationUpdate {
updatedAt: Date;
type: QuestType;
periodStart: Date;
periodEnd: Date;
}

export interface QuestRotationUpdateData {
questRotationUpdate: QuestRotationUpdate;
}

export interface MarkQuestRotationsViewedData {
markQuestRotationsViewed: {
_: boolean;
};
}

export enum ClientQuestEventType {
VisitExplorePage = 'visit_explore_page',
VisitDiscussionsPage = 'visit_discussions_page',
Expand Down Expand Up @@ -260,7 +242,6 @@ export const QUEST_DASHBOARD_QUERY = gql`
amount
}
}
hasNewQuestRotations
}
}
`;
Expand Down Expand Up @@ -422,14 +403,6 @@ export const TRACK_QUEST_EVENT_MUTATION = gql`
}
`;

export const MARK_QUEST_ROTATIONS_VIEWED_MUTATION = gql`
mutation MarkQuestRotationsViewed {
markQuestRotationsViewed {
_
}
}
`;

export const QUEST_UPDATE_SUBSCRIPTION = gql`
subscription QuestUpdate {
questUpdate {
Expand Down
Loading
Loading