From e522f69b1e29c59d8bf1d4700cdc576d8f2fd5a3 Mon Sep 17 00:00:00 2001 From: Ansh Nanda Date: Thu, 16 Nov 2023 15:02:22 -0800 Subject: [PATCH] add store review prompt based on number of sessions --- src/App.native.tsx | 6 ++ src/lib/store-review.ts | 82 +++++++++++++++++++++++++++ src/state/persisted/legacy.ts | 6 ++ src/state/persisted/schema.ts | 12 ++++ src/view/com/profile/FollowButton.tsx | 2 + 5 files changed, 108 insertions(+) create mode 100644 src/lib/store-review.ts diff --git a/src/App.native.tsx b/src/App.native.tsx index af4c3be89c..a108c3311b 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -37,6 +37,7 @@ import * as persisted from '#/state/persisted' import {i18n} from '@lingui/core' import {I18nProvider} from '@lingui/react' import {messages} from './locale/locales/en/messages' +import {listenSessionChangeForStoreReview} from './lib/store-review' i18n.load('en', messages) i18n.activate('en') @@ -55,9 +56,14 @@ function InnerApp() { listenSessionDropped(() => { Toast.show('Sorry! Your session expired. Please log in again.') }) + const lForStoreReview = listenSessionChangeForStoreReview() const account = persisted.get('session').currentAccount resumeSession(account) + + return () => { + lForStoreReview() // cleanup + } }, [resumeSession]) // show nothing prior to init diff --git a/src/lib/store-review.ts b/src/lib/store-review.ts new file mode 100644 index 0000000000..7d016f6e65 --- /dev/null +++ b/src/lib/store-review.ts @@ -0,0 +1,82 @@ +import * as StoreReview from 'expo-store-review' +import * as persisted from '#/state/persisted' +import {AppState} from 'react-native' +import {isWeb} from '#/platform/detection' +import {logger} from '#/logger' + +async function askForStoreReivew() { + if (isWeb) return + + if (await StoreReview.hasAction()) { + await StoreReview.requestReview() + } +} + +async function askForStoreReviewWithDelay() { + if (isWeb) return + + const {lastPromptedAt, numSessions, numFollowed} = + persisted.get('storeReview') + const now = new Date() + const oneWeek = 1000 * 60 * 60 * 24 * 7 + // don't prompt if we've already prompted in the last week + if (lastPromptedAt && now.getTime() - lastPromptedAt.getTime() < oneWeek) { + return + } + // prompt if user has had 100 sessions or followed 50 people + if (numSessions >= 10 || numFollowed >= 50) { + setTimeout(() => { + askForStoreReivew().then(() => { + persisted + .write('storeReview', { + completed: true, + lastPromptedAt: now, + numSessions: numSessions, + numFollowed: numFollowed, + }) + .catch(e => { + logger.error('error writing store review', {error: String(e)}) + }) + }) + }, 5000) // delay asking for 5 seconds + return + } +} + +export async function incrementStoreReviewFollowed() { + if (isWeb) return + + const {numFollowed, ...others} = persisted.get('storeReview') + await persisted.write('storeReview', { + numFollowed: numFollowed + 1, + ...others, + }) + askForStoreReviewWithDelay() +} + +export async function incrementStoreReviewSessions() { + if (isWeb) return + + const {numSessions, ...others} = persisted.get('storeReview') + console.log('incrementStoreReviewSessions', numSessions, others) + await persisted.write('storeReview', { + numSessions: numSessions + 1, + ...others, + }) + askForStoreReviewWithDelay() +} + +export function listenSessionChangeForStoreReview() { + console.log('listenSessionChangeForStoreReview') + + // sets up AppState listener + const l = AppState.addEventListener('change', () => { + if (AppState.currentState === 'active') { + incrementStoreReviewSessions() + } + }) + + return () => { + l.remove() + } +} diff --git a/src/state/persisted/legacy.ts b/src/state/persisted/legacy.ts index fefa7f3725..3d94eeadfb 100644 --- a/src/state/persisted/legacy.ts +++ b/src/state/persisted/legacy.ts @@ -106,6 +106,12 @@ export function transform(legacy: Partial): Schema { onboarding: { step: legacy.onboarding?.step || defaults.onboarding.step, }, + storeReview: { + completed: false, + lastPromptedAt: undefined, + numSessions: 0, + numFollowed: 0, + }, } } diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 93547aa5ba..f6a4da8bdc 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -39,6 +39,12 @@ export const schema = z.object({ onboarding: z.object({ step: z.string(), }), + storeReview: z.object({ + lastPromptedAt: z.date().optional(), + completed: z.boolean(), + numSessions: z.number(), + numFollowed: z.number(), + }), }) export type Schema = z.infer @@ -67,4 +73,10 @@ export const defaults: Schema = { onboarding: { step: 'Home', }, + storeReview: { + lastPromptedAt: undefined, + completed: false, + numSessions: 0, + numFollowed: 0, + }, } diff --git a/src/view/com/profile/FollowButton.tsx b/src/view/com/profile/FollowButton.tsx index 032a910c79..a4318868b8 100644 --- a/src/view/com/profile/FollowButton.tsx +++ b/src/view/com/profile/FollowButton.tsx @@ -8,6 +8,7 @@ import { useProfileUnfollowMutation, } from '#/state/queries/profile' import {Shadow} from '#/state/cache/types' +import {incrementStoreReviewFollowed} from '#/lib/store-review' export function FollowButton({ unfollowedType = 'inverted', @@ -29,6 +30,7 @@ export function FollowButton({ } try { await followMutation.mutateAsync({did: profile.did}) + incrementStoreReviewFollowed() } catch (e: any) { Toast.show(`An issue occurred, please try again.`) }