Skip to content

Commit

Permalink
feat: toast for user that are no longer available to recover (#3552)
Browse files Browse the repository at this point in the history
* feat: display message to user if recover no longer available;

* fix: lint error

* fix: moved onClose inside the queryFn

* fix: removed unused function

* fix: recover modal for user that disabled it;

* feat: added again toast;
fix: not showing modal for user with no streak enabled;

* fix: only display toast for user that clicked on notification;

* refactor: more failsafe patter for guests/streak disabled users

* fix: tests and logic on boot
  • Loading branch information
ilasw authored Sep 30, 2024
1 parent 570d1f3 commit 752a701
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 8 deletions.
12 changes: 11 additions & 1 deletion packages/shared/src/components/modals/BootPopups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,18 @@ export const BootPopups = (): ReactElement => {
* Streak recovery modal
*/
useEffect(() => {
const shouldNotShowStreakUpdates =
!isStreaksEnabled || !isActionsFetched || isDisabledMilestone;
const hasMarkedAction = checkHasCompleted(
ActionType.DisableReadingStreakRecover,
);

if (!alerts.showRecoverStreak || !user || hasMarkedAction) {
if (
shouldNotShowStreakUpdates ||
!alerts.showRecoverStreak ||
!user ||
hasMarkedAction
) {
return;
}
addBootPopup({
Expand All @@ -224,6 +231,9 @@ export const BootPopups = (): ReactElement => {
alerts,
checkHasCompleted,
isActionsFetched,
isDisabledMilestone,
isStreaksEnabled,
shouldHideStreaksModal,
streak,
updateAlerts,
updateLastBootPopup,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { QueryClient } from '@tanstack/react-query';
import { subDays } from 'date-fns';
import { TestBootProvider } from '../../../../__tests__/helpers/boot';
import type { LoggedUser } from '../../../lib/user';
import loggedUser from '../../../../__tests__/fixture/loggedUser';
Expand All @@ -15,8 +16,10 @@ import {
import { mockGraphQL } from '../../../../__tests__/helpers/graphql';
import * as actionHook from '../../../hooks/useActions';
import * as toastHook from '../../../hooks/useToastNotification';
import * as streakHook from '../../../hooks/streaks/useReadingStreak';
import { ActionType } from '../../../graphql/actions';
import Toast from '../../notifications/Toast';
import { DayOfWeek } from '../../../lib/date';

interface TestProps {
user?: LoggedUser | null;
Expand All @@ -32,6 +35,7 @@ const defaultAlerts: Alerts = {
const alertsWithStreakRecovery: Alerts = {
...defaultAlerts,
showRecoverStreak: true,
showStreakMilestone: true,
};

const checkHasCompleted = jest.fn();
Expand Down Expand Up @@ -90,7 +94,7 @@ const mockAlertsMutation = () => {
});
};

const renderComponent = (props: TestProps) => {
const renderComponent = (props: TestProps = {}) => {
const {
user = { ...loggedUser, reputation: 10 },
alerts = alertsWithStreakRecovery,
Expand All @@ -101,6 +105,10 @@ const renderComponent = (props: TestProps) => {
client={queryClient}
auth={{ user }}
alerts={{ alerts, updateAlerts }}
settings={{
loadedSettings: true,
optOutReadingStreak: false,
}}
>
<BootPopups />
<Toast autoDismissNotifications={false} />
Expand All @@ -121,6 +129,21 @@ beforeEach(async () => {
subject: undefined,
});

jest.spyOn(streakHook, 'useReadingStreak').mockReturnValue({
isLoading: false,
isStreaksEnabled: true,
streak: {
current: 10,
max: 10,
total: 12,
weekStart: DayOfWeek.Monday,
lastViewAt: subDays(new Date(), 2),
},
updateStreakConfig: jest.fn(),
checkReadingStreak: jest.fn(),
shouldShowPopup: false,
});

// need to reset the query cache
queryClient.clear();
// need to reset the mock
Expand Down Expand Up @@ -168,7 +191,7 @@ it('should render and fetch initial data if logged user can recover streak', asy
},
);

renderComponent({});
renderComponent();

await waitForNock();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
import { Checkbox } from '../../fields/Checkbox';
import { ModalClose } from '../common/ModalClose';
import { cloudinary } from '../../../lib/image';
import { useReadingStreak } from '../../../hooks/streaks';

export interface StreakRecoverModalProps
extends Pick<ModalProps, 'isOpen' | 'onAfterClose'> {
Expand Down Expand Up @@ -162,14 +163,21 @@ export const StreakRecoverModal = (
props: StreakRecoverModalProps,
): ReactElement => {
const { isOpen, onRequestClose, onAfterClose, user } = props;
const { isStreaksEnabled } = useReadingStreak();

const id = useId();
const { recover, hideForever, onClose, onRecover } = useStreakRecover({
onAfterClose,
onRequestClose,
});

if (!user || !recover.canRecover || recover.isLoading || recover.isDisabled) {
if (
!user ||
!isStreaksEnabled ||
!recover.canRecover ||
recover.isLoading ||
recover.isDisabled
) {
return null;
}

Expand Down
29 changes: 25 additions & 4 deletions packages/shared/src/hooks/streaks/useStreakRecover.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useEffect } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { useToggle } from '../useToggle';
import { useActions } from '../useActions';
import {
Expand All @@ -15,6 +16,7 @@ import { useLogContext } from '../../contexts/LogContext';
import { LogEvent, TargetType } from '../../lib/log';
import { useAlertsContext } from '../../contexts/AlertContext';
import { useAuthContext } from '../../contexts/AuthContext';
import { useReadingStreak } from './useReadingStreak';

interface UseStreakRecoverProps {
onAfterClose?: () => void;
Expand Down Expand Up @@ -51,11 +53,11 @@ export const useStreakRecover = ({
const { logEvent } = useLogContext();
const { updateAlerts } = useAlertsContext();
const { user } = useAuthContext();
const { isStreaksEnabled } = useReadingStreak();
const client = useQueryClient();
const { data, isLoading } = useQuery<StreakQueryData>({
queryKey: generateQueryKey(RequestKey.UserStreakRecover),
queryFn: async () => await gqlClient.request(USER_STREAK_RECOVER_QUERY),
});
const {
query: { streak_restore: streakRestore },
} = useRouter();

const recoverMutation = useMutation({
mutationKey: generateQueryKey(RequestKey.UserStreakRecover),
Expand All @@ -78,6 +80,25 @@ export const useStreakRecover = ({
});
}, [updateAlerts]);

const { data, isLoading } = useQuery<StreakQueryData>({
queryKey: generateQueryKey(RequestKey.UserStreakRecover),
queryFn: async () => {
const res = await gqlClient.request(USER_STREAK_RECOVER_QUERY);

const userCantRecoverInNotificationCenter =
!res?.streakRecover?.canRecover && !!streakRestore;
if (userCantRecoverInNotificationCenter) {
await hideRemoteAlert();
displayToast('Oops, you are no longer eligible to restore your streak');
onRequestClose?.();
onAfterClose?.();
}

return res;
},
enabled: !!user && isStreaksEnabled && !hideForever,
});

const onClose = useCallback(async () => {
if (hideForever) {
await completeAction(ActionType.DisableReadingStreakRecover);
Expand Down

0 comments on commit 752a701

Please sign in to comment.