From 9d4101855ac25a51a959c1c2686eb7983768260d Mon Sep 17 00:00:00 2001 From: Martino Cesari Tomba <60693085+forrest57@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:55:34 +0100 Subject: [PATCH] chore: [IOCOM-1763] Refactor of push notification engagement screen display logic (#6464) ## Short description update of push notification screen display logic following the intended final behaviour ## List of changes proposed in this pull request - addition of missing selectors for engagement screen display logic - addition of missing selector in engagement banner display logic - addition of non-persisted state for engagement banner logic - tests fix and missing test ## How to test with the dev-server active, update `LANDING_SCREEN_BANNERS_ENABLED_MAP` to have `PUSH_NOTIFICATIONS_REMINDER:true`, then disable push notifications for IO and log out of the app if you are in an active session. Then, after launching the app again, make sure that the behaviour is as follows: 1) on login, you should be prompted to enable notifications in the app, and no matter the choice you should not see the push engagement screen or the push notifications banner in the messages home 2) after closing and re-opening the app, if push notifications are still disabled, you should see the engagement screen, but not the push notifications banner in the homescreen 3) after closing and re-opening once more, you should still not see the engagement screen, but the banner should be now shown. if push notifications are enabled, you should never see either the engagement screen or the push notifications banner. --- .../__snapshots__/index.test.ts.snap | 2 +- .../__snapshots__/reducer.test.ts.snap | 2 +- .../utils/landingScreenBannerMap.tsx | 2 +- .../SystemNotificationPermissionsScreen.tsx | 2 +- ...stemNotificationPermissionsScreen.test.tsx | 2 +- .../actions/__tests__/environment.test.ts | 12 ++++- .../actions/__tests__/userBehaviour.test.ts | 9 ---- .../store/actions/environment.ts | 6 ++- .../store/actions/userBehaviour.ts | 4 -- .../__snapshots__/environment.test.ts.snap | 1 + .../__snapshots__/index.test.ts.snap | 16 +++--- .../__snapshots__/userBehaviour.test.ts.snap | 7 +-- .../reducers/__tests__/environment.test.ts | 29 ++++++++--- .../store/reducers/__tests__/index.test.ts | 51 +++++++++++-------- .../reducers/__tests__/userBehaviour.test.ts | 25 +++------ .../store/reducers/environment.ts | 10 +++- .../pushNotifications/store/reducers/index.ts | 24 ++++----- .../store/reducers/userBehaviour.ts | 37 +++----------- .../notificationsBannerDismissed.test.ts | 9 ++-- .../store/selectors/index.ts | 4 ++ .../selectors/notificationsBannerDismissed.ts | 4 +- 21 files changed, 129 insertions(+), 129 deletions(-) diff --git a/ts/features/common/store/reducers/__tests__/__snapshots__/index.test.ts.snap b/ts/features/common/store/reducers/__tests__/__snapshots__/index.test.ts.snap index 0fbb8caac96..d1dfb3bc2a9 100644 --- a/ts/features/common/store/reducers/__tests__/__snapshots__/index.test.ts.snap +++ b/ts/features/common/store/reducers/__tests__/__snapshots__/index.test.ts.snap @@ -136,7 +136,7 @@ exports[`featuresPersistor should match snapshot 1`] = ` }, "landingBanners": { "ITW_DISCOVERY": true, - "PUSH_NOTIFICATIONS_REMINDER": false, + "PUSH_NOTIFICATIONS_REMINDER": true, "SETTINGS_DISCOVERY": true, }, "loginFeatures": { diff --git a/ts/features/landingScreenMultiBanner/store/__tests__/__snapshots__/reducer.test.ts.snap b/ts/features/landingScreenMultiBanner/store/__tests__/__snapshots__/reducer.test.ts.snap index edbfabfa467..f1f67f85871 100644 --- a/ts/features/landingScreenMultiBanner/store/__tests__/__snapshots__/reducer.test.ts.snap +++ b/ts/features/landingScreenMultiBanner/store/__tests__/__snapshots__/reducer.test.ts.snap @@ -3,7 +3,7 @@ exports[`landingScreenBannersReducer should match snapshot: undefined_no_action 1`] = ` { "ITW_DISCOVERY": true, - "PUSH_NOTIFICATIONS_REMINDER": false, + "PUSH_NOTIFICATIONS_REMINDER": true, "SETTINGS_DISCOVERY": true, } `; diff --git a/ts/features/landingScreenMultiBanner/utils/landingScreenBannerMap.tsx b/ts/features/landingScreenMultiBanner/utils/landingScreenBannerMap.tsx index 51643b7c9b8..68f6d682821 100644 --- a/ts/features/landingScreenMultiBanner/utils/landingScreenBannerMap.tsx +++ b/ts/features/landingScreenMultiBanner/utils/landingScreenBannerMap.tsx @@ -22,7 +22,7 @@ export type LandingScreenBannerId = keyof typeof LANDING_SCREEN_BANNERS_ENABLED_MAP; export const LANDING_SCREEN_BANNERS_ENABLED_MAP = { - PUSH_NOTIFICATIONS_REMINDER: false, + PUSH_NOTIFICATIONS_REMINDER: true, ITW_DISCOVERY: true, SETTINGS_DISCOVERY: true } as const; diff --git a/ts/features/pushNotifications/screens/SystemNotificationPermissionsScreen.tsx b/ts/features/pushNotifications/screens/SystemNotificationPermissionsScreen.tsx index 67363068f2b..80f56f2a509 100644 --- a/ts/features/pushNotifications/screens/SystemNotificationPermissionsScreen.tsx +++ b/ts/features/pushNotifications/screens/SystemNotificationPermissionsScreen.tsx @@ -4,12 +4,12 @@ import { useIONavigation } from "../../../navigation/params/AppParamsList"; import { openSystemNotificationSettingsScreen } from "../utils"; import I18n from "../../../i18n"; import { useIODispatch } from "../../../store/hooks"; -import { setEngagementScreenShown } from "../store/actions/userBehaviour"; import { trackSystemNotificationPermissionScreenOutcome, trackSystemNotificationPermissionScreenShown } from "../analytics"; import { IOScrollViewCentredContent } from "../../../components/ui/IOScrollViewCentredContent"; +import { setEngagementScreenShown } from "../store/actions/environment"; export const SystemNotificationPermissionsScreen = () => { const dispatch = useIODispatch(); diff --git a/ts/features/pushNotifications/screens/__tests__/SystemNotificationPermissionsScreen.test.tsx b/ts/features/pushNotifications/screens/__tests__/SystemNotificationPermissionsScreen.test.tsx index 292649a6c19..d6f1d415e53 100644 --- a/ts/features/pushNotifications/screens/__tests__/SystemNotificationPermissionsScreen.test.tsx +++ b/ts/features/pushNotifications/screens/__tests__/SystemNotificationPermissionsScreen.test.tsx @@ -11,9 +11,9 @@ import { mockAccessibilityInfo } from "../../../../utils/testAccessibility"; import { renderScreenWithNavigationStoreContext } from "../../../../utils/testWrapper"; import * as analytics from "../../analytics"; import { NOTIFICATIONS_ROUTES } from "../../navigation/routes"; -import { setEngagementScreenShown } from "../../store/actions/userBehaviour"; import * as utils from "../../utils"; import { SystemNotificationPermissionsScreen } from "../SystemNotificationPermissionsScreen"; +import { setEngagementScreenShown } from "../../store/actions/environment"; const mockGoBack = jest.fn(); const mockSetNavigationOptions = jest.fn(); diff --git a/ts/features/pushNotifications/store/actions/__tests__/environment.test.ts b/ts/features/pushNotifications/store/actions/__tests__/environment.test.ts index 1b79c3d036e..52706ac6bd8 100644 --- a/ts/features/pushNotifications/store/actions/__tests__/environment.test.ts +++ b/ts/features/pushNotifications/store/actions/__tests__/environment.test.ts @@ -1,4 +1,7 @@ -import { setPushPermissionsRequestDuration } from "../environment"; +import { + setEngagementScreenShown, + setPushPermissionsRequestDuration +} from "../environment"; describe("setPushPermissionsRequestDuration", () => { it("Should match expected values", () => { @@ -7,3 +10,10 @@ describe("setPushPermissionsRequestDuration", () => { expect(action.payload).toBe(1000); }); }); +describe("setEngagementScreenShown", () => { + it("Should match expected values", () => { + const action = setEngagementScreenShown(); + expect(action.type).toBe("SET_ENGAGEMENT_SCREEN_SHOWN"); + expect(action.payload).toBe(undefined); + }); +}); diff --git a/ts/features/pushNotifications/store/actions/__tests__/userBehaviour.test.ts b/ts/features/pushNotifications/store/actions/__tests__/userBehaviour.test.ts index 29ba5e2f9fc..131c2e01870 100644 --- a/ts/features/pushNotifications/store/actions/__tests__/userBehaviour.test.ts +++ b/ts/features/pushNotifications/store/actions/__tests__/userBehaviour.test.ts @@ -1,18 +1,9 @@ import { resetNotificationBannerDismissState, - setEngagementScreenShown, setPushNotificationBannerForceDismissed, setUserDismissedNotificationsBanner } from "../userBehaviour"; -describe("setEngagementScreenShown", () => { - it("Should match expected values", () => { - const action = setEngagementScreenShown(); - expect(action.type).toBe("SET_ENGAGEMENT_SCREEN_SHOWN"); - expect(action.payload).toBe(undefined); - }); -}); - describe("setUserDismissedNotificationsBanner", () => { it("Should match expected values", () => { const action = setUserDismissedNotificationsBanner(); diff --git a/ts/features/pushNotifications/store/actions/environment.ts b/ts/features/pushNotifications/store/actions/environment.ts index ca738948a0c..c34616e3f52 100644 --- a/ts/features/pushNotifications/store/actions/environment.ts +++ b/ts/features/pushNotifications/store/actions/environment.ts @@ -6,7 +6,11 @@ export const updateSystemNotificationsEnabled = createStandardAction( export const setPushPermissionsRequestDuration = createStandardAction( "SET_PUSH_PERMISSIONS_REQUEST_DURATION" )(); +export const setEngagementScreenShown = createStandardAction( + "SET_ENGAGEMENT_SCREEN_SHOWN" +)(); export type NotificationPermissionsActions = | ActionType - | ActionType; + | ActionType + | ActionType; diff --git a/ts/features/pushNotifications/store/actions/userBehaviour.ts b/ts/features/pushNotifications/store/actions/userBehaviour.ts index 3a75dd57572..626947d9810 100644 --- a/ts/features/pushNotifications/store/actions/userBehaviour.ts +++ b/ts/features/pushNotifications/store/actions/userBehaviour.ts @@ -1,8 +1,5 @@ import { ActionType, createStandardAction } from "typesafe-actions"; -export const setEngagementScreenShown = createStandardAction( - "SET_ENGAGEMENT_SCREEN_SHOWN" -)(); export const setUserDismissedNotificationsBanner = createStandardAction( "SET_USER_DISMISSED_NOTIFICATIONS_BANNER" )(); @@ -14,7 +11,6 @@ export const resetNotificationBannerDismissState = createStandardAction( )(); export type UserBehaviourActions = - | ActionType | ActionType | ActionType | ActionType; diff --git a/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/environment.test.ts.snap b/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/environment.test.ts.snap index ee2a162357c..8b8ac635c15 100644 --- a/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/environment.test.ts.snap +++ b/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/environment.test.ts.snap @@ -3,6 +3,7 @@ exports[`environment reducer initial state should match expected values 1`] = ` { "applicationInitialized": false, + "engagementScreenShownThisSession": false, "onboardingInstructionsShown": false, "pushNotificationPermissionsRequestDuration": undefined, "systemNotificationsEnabled": false, diff --git a/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/index.test.ts.snap b/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/index.test.ts.snap index 377499c3313..e54e97d6a54 100644 --- a/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/index.test.ts.snap +++ b/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/index.test.ts.snap @@ -4,6 +4,7 @@ exports[`Main pushNotifications reducer notificationsReducer initial state shoul { "environment": { "applicationInitialized": false, + "engagementScreenShownThisSession": false, "onboardingInstructionsShown": false, "pushNotificationPermissionsRequestDuration": undefined, "systemNotificationsEnabled": false, @@ -14,11 +15,8 @@ exports[`Main pushNotifications reducer notificationsReducer initial state shoul }, "pendingMessage": null, "userBehaviour": { - "engagementScreenShown": false, - "pushNotificationsBanner": { - "forceDismissionDate": undefined, - "timesDismissed": 0, - }, + "pushNotificationBannerDismissalCount": 0, + "pushNotificationBannerForceDismissionDate": undefined, }, } `; @@ -27,6 +25,7 @@ exports[`Main pushNotifications reducer persistedNotificationsReducer initial st { "environment": { "applicationInitialized": false, + "engagementScreenShownThisSession": false, "onboardingInstructionsShown": false, "pushNotificationPermissionsRequestDuration": undefined, "systemNotificationsEnabled": false, @@ -37,11 +36,8 @@ exports[`Main pushNotifications reducer persistedNotificationsReducer initial st }, "pendingMessage": null, "userBehaviour": { - "engagementScreenShown": false, - "pushNotificationsBanner": { - "forceDismissionDate": undefined, - "timesDismissed": 0, - }, + "pushNotificationBannerDismissalCount": 0, + "pushNotificationBannerForceDismissionDate": undefined, }, } `; diff --git a/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/userBehaviour.test.ts.snap b/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/userBehaviour.test.ts.snap index 569410e32a2..f8577306325 100644 --- a/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/userBehaviour.test.ts.snap +++ b/ts/features/pushNotifications/store/reducers/__tests__/__snapshots__/userBehaviour.test.ts.snap @@ -2,10 +2,7 @@ exports[`userBehaviourReducer Should match snapshot 1`] = ` { - "engagementScreenShown": false, - "pushNotificationsBanner": { - "forceDismissionDate": undefined, - "timesDismissed": 0, - }, + "pushNotificationBannerDismissalCount": 0, + "pushNotificationBannerForceDismissionDate": undefined, } `; diff --git a/ts/features/pushNotifications/store/reducers/__tests__/environment.test.ts b/ts/features/pushNotifications/store/reducers/__tests__/environment.test.ts index 708085a11c4..489aa944e77 100644 --- a/ts/features/pushNotifications/store/reducers/__tests__/environment.test.ts +++ b/ts/features/pushNotifications/store/reducers/__tests__/environment.test.ts @@ -4,14 +4,15 @@ import { } from "../../../../../store/actions/application"; import { GlobalState } from "../../../../../store/reducers/types"; import { + setEngagementScreenShown, setPushPermissionsRequestDuration, updateSystemNotificationsEnabled } from "../../actions/environment"; import { notificationsInfoScreenConsent } from "../../actions/profileNotificationPermissions"; import { areNotificationPermissionsEnabled, - INITIAL_STATE, - environmentReducer + environmentReducer, + INITIAL_STATE } from "../environment"; describe("environment reducer initial state", () => { @@ -42,7 +43,8 @@ describe("environmentReducer", () => { { applicationInitialized: false, onboardingInstructionsShown: false, - systemNotificationsEnabled: true + systemNotificationsEnabled: true, + engagementScreenShownThisSession: false }, updateSystemNotificationsEnabled(false) ); @@ -55,7 +57,8 @@ describe("environmentReducer", () => { { applicationInitialized: false, onboardingInstructionsShown: false, - systemNotificationsEnabled: false + systemNotificationsEnabled: false, + engagementScreenShownThisSession: false }, notificationsInfoScreenConsent() ); @@ -68,7 +71,8 @@ describe("environmentReducer", () => { { applicationInitialized: false, onboardingInstructionsShown: false, - systemNotificationsEnabled: false + systemNotificationsEnabled: false, + engagementScreenShownThisSession: false }, applicationInitialized({ actionsToWaitFor: [] }) ); @@ -81,7 +85,8 @@ describe("environmentReducer", () => { { applicationInitialized: true, onboardingInstructionsShown: false, - systemNotificationsEnabled: false + systemNotificationsEnabled: false, + engagementScreenShownThisSession: false }, setPushPermissionsRequestDuration(100) ); @@ -89,6 +94,18 @@ describe("environmentReducer", () => { 100 ); }); + it("'engagementScreenShownThisSession' should be 'true' after receiving 'setEngagementScreenShown'", () => { + const userBehaviourState = environmentReducer( + { + applicationInitialized: true, + onboardingInstructionsShown: false, + systemNotificationsEnabled: false, + engagementScreenShownThisSession: false + }, + setEngagementScreenShown() + ); + expect(userBehaviourState.engagementScreenShownThisSession).toBe(true); + }); }); describe("areNotificationPermissionsEnabled selector", () => { diff --git a/ts/features/pushNotifications/store/reducers/__tests__/index.test.ts b/ts/features/pushNotifications/store/reducers/__tests__/index.test.ts index 7f6f448613a..317e794f10e 100644 --- a/ts/features/pushNotifications/store/reducers/__tests__/index.test.ts +++ b/ts/features/pushNotifications/store/reducers/__tests__/index.test.ts @@ -48,29 +48,38 @@ describe("shouldShowEngagementScreenSelector", () => { [false, true].forEach(applicationInitialized => [false, true].forEach(onboardingInstructionsShown => [false, true].forEach(systemNotificationsEnabled => - [false, true].forEach(engagementScreenShown => { - const expectedOutput = - applicationInitialized && - !onboardingInstructionsShown && - !systemNotificationsEnabled && - !engagementScreenShown; - it(`Should output '${expectedOutput}' when 'applicationInitialized' is '${applicationInitialized}' , 'onboardingInstructionsShown' is '${onboardingInstructionsShown}' , 'systemNotificationsEnabled' is '${systemNotificationsEnabled} ' and 'engagementScreenShown' is '${engagementScreenShown}' `, () => { - const state = { - notifications: { - environment: { - applicationInitialized, - onboardingInstructionsShown, - systemNotificationsEnabled + [false, true].forEach(userFromSuccessLogin => + [10, 900].forEach(pushNotificationPermissionsRequestDuration => { + const expectedOutput = + userFromSuccessLogin && + !systemNotificationsEnabled && + pushNotificationPermissionsRequestDuration < 750 && + applicationInitialized && + !onboardingInstructionsShown; + + it(`Should output '${expectedOutput}' when 'applicationInitialized' is '${applicationInitialized}' , 'onboardingInstructionsShown' is '${onboardingInstructionsShown}' , 'systemNotificationsEnabled' is '${systemNotificationsEnabled} ' `, () => { + const state = { + features: { + loginFeatures: { + loginInfo: { + userFromSuccessLogin + } + } }, - userBehaviour: { - engagementScreenShown + notifications: { + environment: { + applicationInitialized, + onboardingInstructionsShown, + systemNotificationsEnabled, + pushNotificationPermissionsRequestDuration + } } - } - } as GlobalState; - const output = shouldShowEngagementScreenSelector(state); - expect(output).toBe(expectedOutput); - }); - }) + } as GlobalState; + const output = shouldShowEngagementScreenSelector(state); + expect(output).toBe(expectedOutput); + }); + }) + ) ) ) ); diff --git a/ts/features/pushNotifications/store/reducers/__tests__/userBehaviour.test.ts b/ts/features/pushNotifications/store/reducers/__tests__/userBehaviour.test.ts index 79e780415f1..1f0309f1ca0 100644 --- a/ts/features/pushNotifications/store/reducers/__tests__/userBehaviour.test.ts +++ b/ts/features/pushNotifications/store/reducers/__tests__/userBehaviour.test.ts @@ -1,16 +1,12 @@ import { applicationChangeState } from "../../../../../store/actions/application"; import { resetNotificationBannerDismissState, - setEngagementScreenShown, setPushNotificationBannerForceDismissed, setUserDismissedNotificationsBanner } from "../../actions/userBehaviour"; -import { INITIAL_STATE, userBehaviourReducer } from "../userBehaviour"; +import { userBehaviourReducer, UserBehaviourState } from "../userBehaviour"; describe("userBehaviourReducer", () => { - it("INITIAL_STATE should match expected values", () => { - expect(INITIAL_STATE.engagementScreenShown).toBe(false); - }); it("Should match snapshot", () => { const userBehaviourState = userBehaviourReducer( undefined, @@ -18,19 +14,12 @@ describe("userBehaviourReducer", () => { ); expect(userBehaviourState).toMatchSnapshot(); }); - it("'engagementScreenShown' should be 'true' after receiving 'setEngagementScreenShown'", () => { - const userBehaviourState = userBehaviourReducer( - undefined, - setEngagementScreenShown() - ); - expect(userBehaviourState.engagementScreenShown).toBe(true); - }); it(' "pushNotificationsBanner.timesDismissed" should be "1" after receiving "setUserDismissedNotificationsBanner"', () => { const userBehaviourState = userBehaviourReducer( undefined, setUserDismissedNotificationsBanner() ); - expect(userBehaviourState.pushNotificationsBanner.timesDismissed).toBe(1); + expect(userBehaviourState.pushNotificationBannerDismissalCount).toBe(1); }); it(' "pushNotificationsBanner.forceDismissionDate" should be "Date" after receiving "setPushNotificationBannerForceDismissed"', () => { const userBehaviourState = userBehaviourReducer( @@ -39,7 +28,7 @@ describe("userBehaviourReducer", () => { ); expect( - typeof userBehaviourState.pushNotificationsBanner.forceDismissionDate + typeof userBehaviourState.pushNotificationBannerForceDismissionDate ).toBe("number"); }); it("pushNotificationsBanner should match initial state upon receiving 'resetNotificationBannerDismissState", () => { @@ -47,9 +36,9 @@ describe("userBehaviourReducer", () => { undefined, resetNotificationBannerDismissState() ); - expect(userBehaviourState.pushNotificationsBanner).toEqual({ - timesDismissed: 0, - forceDismissionDate: undefined - }); + expect(userBehaviourState).toEqual({ + pushNotificationBannerDismissalCount: 0, + pushNotificationBannerForceDismissionDate: undefined + } as UserBehaviourState); }); }); diff --git a/ts/features/pushNotifications/store/reducers/environment.ts b/ts/features/pushNotifications/store/reducers/environment.ts index 1611555416f..6a5b1276d5b 100644 --- a/ts/features/pushNotifications/store/reducers/environment.ts +++ b/ts/features/pushNotifications/store/reducers/environment.ts @@ -1,6 +1,7 @@ import { getType } from "typesafe-actions"; import { Action } from "../../../../store/actions/types"; import { + setEngagementScreenShown, setPushPermissionsRequestDuration, updateSystemNotificationsEnabled } from "../actions/environment"; @@ -13,13 +14,15 @@ export type EnvironmentState = { onboardingInstructionsShown: boolean; systemNotificationsEnabled: boolean; pushNotificationPermissionsRequestDuration?: number; + engagementScreenShownThisSession: boolean; }; export const INITIAL_STATE = { applicationInitialized: false, onboardingInstructionsShown: false, systemNotificationsEnabled: false, - pushNotificationPermissionsRequestDuration: undefined + pushNotificationPermissionsRequestDuration: undefined, + engagementScreenShownThisSession: false }; export const environmentReducer = ( @@ -38,6 +41,11 @@ export const environmentReducer = ( ...state, pushNotificationPermissionsRequestDuration: action.payload }; + case getType(setEngagementScreenShown): + return { + ...state, + engagementScreenShownThisSession: true + }; } return state; }; diff --git a/ts/features/pushNotifications/store/reducers/index.ts b/ts/features/pushNotifications/store/reducers/index.ts index d77f6dfbc6b..cc1be1f449e 100644 --- a/ts/features/pushNotifications/store/reducers/index.ts +++ b/ts/features/pushNotifications/store/reducers/index.ts @@ -1,5 +1,4 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; -import { merge } from "lodash"; import { combineReducers } from "redux"; import { createMigrate, @@ -12,6 +11,8 @@ import { import { Action } from "../../../../store/actions/types"; import { GlobalState } from "../../../../store/reducers/types"; import { isDevEnv } from "../../../../utils/environment"; +import { userFromSuccessLoginSelector } from "../../../login/info/store/selectors"; +import { hasUserSeenSystemNotificationsPromptSelector } from "../selectors"; import { environmentReducer, EnvironmentState } from "./environment"; import { installationReducer, InstallationState } from "./installation"; import { pendingMessageReducer, PendingMessageState } from "./pendingMessage"; @@ -22,16 +23,14 @@ export const NOTIFICATIONS_STORE_VERSION = 0; export type PersistedNotificationsState = NotificationsState & PersistPartial; const migrations: MigrationManifest = { - // Add new push notifications banner dismissal feature - "0": (state: PersistedState) => - merge(state, { - userBehaviour: { - pushNotificationsBanner: { - timesDismissed: 0, - forceDismissionDate: undefined - } - } - } as NotificationsState) + // Add new push notifications banner dismissal feature, also removal of old engagement screen logic + "0": (state: PersistedState) => ({ + ...state, + userBehaviour: { + pushNotificationBannerDismissalCount: 0, + pushNotificationBannerForceDismissionDate: undefined + } + }) }; export type NotificationsState = { @@ -64,7 +63,8 @@ export const persistedNotificationsReducer = persistReducer< >(notificationsPersistConfig, notificationsReducer); export const shouldShowEngagementScreenSelector = (state: GlobalState) => + userFromSuccessLoginSelector(state) && !state.notifications.environment.systemNotificationsEnabled && - !state.notifications.userBehaviour.engagementScreenShown && + !hasUserSeenSystemNotificationsPromptSelector(state) && state.notifications.environment.applicationInitialized && !state.notifications.environment.onboardingInstructionsShown; diff --git a/ts/features/pushNotifications/store/reducers/userBehaviour.ts b/ts/features/pushNotifications/store/reducers/userBehaviour.ts index bc46d944a67..a3cae5f2805 100644 --- a/ts/features/pushNotifications/store/reducers/userBehaviour.ts +++ b/ts/features/pushNotifications/store/reducers/userBehaviour.ts @@ -2,29 +2,18 @@ import { getType } from "typesafe-actions"; import { Action } from "../../../../store/actions/types"; import { resetNotificationBannerDismissState, - setEngagementScreenShown, setPushNotificationBannerForceDismissed, setUserDismissedNotificationsBanner } from "../actions/userBehaviour"; export type UserBehaviourState = { - engagementScreenShown: boolean; - pushNotificationsBanner: { - timesDismissed: number; - forceDismissionDate?: number; - }; -}; - -const INITIAL_BANNER_STATE = { - timesDismissed: 0, - forceDismissionDate: undefined + pushNotificationBannerDismissalCount: number; + pushNotificationBannerForceDismissionDate?: number; }; export const INITIAL_STATE: UserBehaviourState = { - engagementScreenShown: false, - pushNotificationsBanner: { - ...INITIAL_BANNER_STATE - } + pushNotificationBannerDismissalCount: 0, + pushNotificationBannerForceDismissionDate: undefined }; export const userBehaviourReducer = ( @@ -32,30 +21,20 @@ export const userBehaviourReducer = ( action: Action ): UserBehaviourState => { switch (action.type) { - case getType(setEngagementScreenShown): - return { ...state, engagementScreenShown: true }; case getType(setUserDismissedNotificationsBanner): return { ...state, - pushNotificationsBanner: { - ...state.pushNotificationsBanner, - timesDismissed: state.pushNotificationsBanner.timesDismissed + 1 - } + pushNotificationBannerDismissalCount: + state.pushNotificationBannerDismissalCount + 1 }; case getType(setPushNotificationBannerForceDismissed): return { ...state, - pushNotificationsBanner: { - ...state.pushNotificationsBanner, - forceDismissionDate: new Date().getTime() - } + pushNotificationBannerForceDismissionDate: new Date().getTime() }; case getType(resetNotificationBannerDismissState): return { - ...state, - pushNotificationsBanner: { - ...INITIAL_BANNER_STATE - } + ...INITIAL_STATE }; } return state; diff --git a/ts/features/pushNotifications/store/selectors/__tests__/notificationsBannerDismissed.test.ts b/ts/features/pushNotifications/store/selectors/__tests__/notificationsBannerDismissed.test.ts index 5d48012abad..e80a3d48610 100644 --- a/ts/features/pushNotifications/store/selectors/__tests__/notificationsBannerDismissed.test.ts +++ b/ts/features/pushNotifications/store/selectors/__tests__/notificationsBannerDismissed.test.ts @@ -6,6 +6,7 @@ import { shouldResetNotificationBannerDismissStateSelector, timesPushNotificationBannerDismissedSelector } from "../notificationsBannerDismissed"; +import { UserBehaviourState } from "../../reducers/userBehaviour"; type TestStateProps = { timesDismissed?: number; @@ -31,11 +32,9 @@ const getTestState = ({ }, notifications: { userBehaviour: { - pushNotificationsBanner: { - timesDismissed: timesDismissed ?? 0, - forceDismissionDate - } - } + pushNotificationBannerDismissalCount: timesDismissed ?? 0, + pushNotificationBannerForceDismissionDate: forceDismissionDate + } as UserBehaviourState } } as unknown as GlobalState); diff --git a/ts/features/pushNotifications/store/selectors/index.ts b/ts/features/pushNotifications/store/selectors/index.ts index a476aaca1bb..c46ccfcaafe 100644 --- a/ts/features/pushNotifications/store/selectors/index.ts +++ b/ts/features/pushNotifications/store/selectors/index.ts @@ -47,9 +47,13 @@ export const isPushNotificationsBannerRenderableSelector = ( const hasUserSeenSystemNotificationsPrompt = hasUserSeenSystemNotificationsPromptSelector(state); + const engagementScreenShownThisSession = + state.notifications.environment.engagementScreenShownThisSession; + return ( !isForceDismissed && !isFullLogin && + !engagementScreenShownThisSession && !notificationsEnabled && !hasUserSeenSystemNotificationsPrompt ); diff --git a/ts/features/pushNotifications/store/selectors/notificationsBannerDismissed.ts b/ts/features/pushNotifications/store/selectors/notificationsBannerDismissed.ts index 31aa0744107..93bc63a595b 100644 --- a/ts/features/pushNotifications/store/selectors/notificationsBannerDismissed.ts +++ b/ts/features/pushNotifications/store/selectors/notificationsBannerDismissed.ts @@ -7,11 +7,11 @@ const NEW_MESSAGES_COUNT_TO_RESET_FORCE_DISMISS = 4; export const pushNotificationsBannerForceDismissionDateSelector = ( state: GlobalState ) => - state.notifications.userBehaviour.pushNotificationsBanner.forceDismissionDate; + state.notifications.userBehaviour.pushNotificationBannerForceDismissionDate; export const timesPushNotificationBannerDismissedSelector = ( state: GlobalState -) => state.notifications.userBehaviour.pushNotificationsBanner.timesDismissed; +) => state.notifications.userBehaviour.pushNotificationBannerDismissalCount; export const shouldResetNotificationBannerDismissStateSelector = ( state: GlobalState