add store review prompt based on number of sessions
This commit is contained in:
@@ -37,6 +37,7 @@ import * as persisted from '#/state/persisted'
|
|||||||
import {i18n} from '@lingui/core'
|
import {i18n} from '@lingui/core'
|
||||||
import {I18nProvider} from '@lingui/react'
|
import {I18nProvider} from '@lingui/react'
|
||||||
import {messages} from './locale/locales/en/messages'
|
import {messages} from './locale/locales/en/messages'
|
||||||
|
import {listenSessionChangeForStoreReview} from './lib/store-review'
|
||||||
i18n.load('en', messages)
|
i18n.load('en', messages)
|
||||||
i18n.activate('en')
|
i18n.activate('en')
|
||||||
|
|
||||||
@@ -55,9 +56,14 @@ function InnerApp() {
|
|||||||
listenSessionDropped(() => {
|
listenSessionDropped(() => {
|
||||||
Toast.show('Sorry! Your session expired. Please log in again.')
|
Toast.show('Sorry! Your session expired. Please log in again.')
|
||||||
})
|
})
|
||||||
|
const lForStoreReview = listenSessionChangeForStoreReview()
|
||||||
|
|
||||||
const account = persisted.get('session').currentAccount
|
const account = persisted.get('session').currentAccount
|
||||||
resumeSession(account)
|
resumeSession(account)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
lForStoreReview() // cleanup
|
||||||
|
}
|
||||||
}, [resumeSession])
|
}, [resumeSession])
|
||||||
|
|
||||||
// show nothing prior to init
|
// show nothing prior to init
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -106,6 +106,12 @@ export function transform(legacy: Partial<LegacySchema>): Schema {
|
|||||||
onboarding: {
|
onboarding: {
|
||||||
step: legacy.onboarding?.step || defaults.onboarding.step,
|
step: legacy.onboarding?.step || defaults.onboarding.step,
|
||||||
},
|
},
|
||||||
|
storeReview: {
|
||||||
|
completed: false,
|
||||||
|
lastPromptedAt: undefined,
|
||||||
|
numSessions: 0,
|
||||||
|
numFollowed: 0,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ export const schema = z.object({
|
|||||||
onboarding: z.object({
|
onboarding: z.object({
|
||||||
step: z.string(),
|
step: z.string(),
|
||||||
}),
|
}),
|
||||||
|
storeReview: z.object({
|
||||||
|
lastPromptedAt: z.date().optional(),
|
||||||
|
completed: z.boolean(),
|
||||||
|
numSessions: z.number(),
|
||||||
|
numFollowed: z.number(),
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
export type Schema = z.infer<typeof schema>
|
export type Schema = z.infer<typeof schema>
|
||||||
|
|
||||||
@@ -67,4 +73,10 @@ export const defaults: Schema = {
|
|||||||
onboarding: {
|
onboarding: {
|
||||||
step: 'Home',
|
step: 'Home',
|
||||||
},
|
},
|
||||||
|
storeReview: {
|
||||||
|
lastPromptedAt: undefined,
|
||||||
|
completed: false,
|
||||||
|
numSessions: 0,
|
||||||
|
numFollowed: 0,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
useProfileUnfollowMutation,
|
useProfileUnfollowMutation,
|
||||||
} from '#/state/queries/profile'
|
} from '#/state/queries/profile'
|
||||||
import {Shadow} from '#/state/cache/types'
|
import {Shadow} from '#/state/cache/types'
|
||||||
|
import {incrementStoreReviewFollowed} from '#/lib/store-review'
|
||||||
|
|
||||||
export function FollowButton({
|
export function FollowButton({
|
||||||
unfollowedType = 'inverted',
|
unfollowedType = 'inverted',
|
||||||
@@ -29,6 +30,7 @@ export function FollowButton({
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await followMutation.mutateAsync({did: profile.did})
|
await followMutation.mutateAsync({did: profile.did})
|
||||||
|
incrementStoreReviewFollowed()
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
Toast.show(`An issue occurred, please try again.`)
|
Toast.show(`An issue occurred, please try again.`)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user