From 15748961505d7eadb337a5865f6ef8bf02ae02d6 Mon Sep 17 00:00:00 2001 From: Jon Bindbeutel Date: Fri, 13 Dec 2024 09:10:46 -0500 Subject: [PATCH] Feature/10030+10028 create analytics and trigger (#10279) Co-authored-by: rbontrager --- VAMobile/e2e/tests/utils.ts | 36 +++++----- VAMobile/src/App.tsx | 2 +- .../api/appointments/cancelAppointment.tsx | 4 +- .../downloadEFolderDocument.tsx | 13 ++-- .../api/contactInformation/deleteEmail.tsx | 3 +- .../api/contactInformation/saveAddress.tsx | 3 +- .../src/api/contactInformation/saveEmail.tsx | 3 +- .../contactInformation/savePhoneNumber.tsx | 3 +- .../downloadDecisionLetter.tsx | 9 +-- .../api/demographics/updateGenderIdentity.tsx | 3 +- .../api/demographics/updatePreferredName.tsx | 3 +- .../src/api/directDeposit/updateBankInfo.tsx | 3 +- VAMobile/src/api/letters/downloadLetter.tsx | 8 ++- .../src/api/prescriptions/requestRefills.tsx | 3 +- .../src/api/secureMessaging/saveDraft.tsx | 3 +- .../src/api/secureMessaging/sendMessage.tsx | 3 +- VAMobile/src/constants/analytics.ts | 46 +++++++------ .../AppealDetailsScreen.tsx | 7 +- .../ClaimDetailsScreen/ClaimDetailsScreen.tsx | 7 +- .../DisabilityRatingsScreen.tsx | 7 +- .../PastAppointmentDetails.tsx | 7 +- .../UpcomingAppointmentDetails.tsx | 7 +- .../PrescriptionDetails.tsx | 7 +- .../RefillTrackingDetails.tsx | 7 +- .../ViewMessage/ViewMessageScreen.tsx | 7 +- .../ContactInformationScreen.tsx | 5 +- .../PersonalInformationScreen.tsx | 5 +- .../DeveloperScreen/DeveloperScreen.tsx | 1 - .../InAppFeedbackScreen.tsx | 28 +++++--- .../VeteranStatusScreen.tsx | 5 +- .../PaymentDetailsScreen.tsx | 7 +- VAMobile/src/translations/en/common.json | 1 + VAMobile/src/utils/hooks/index.tsx | 5 +- VAMobile/src/utils/inAppReviews.tsx | 66 ++++++++++++++----- VAMobile/src/utils/remoteConfig.test.ts | 1 + VAMobile/src/utils/remoteConfig.ts | 3 + 36 files changed, 212 insertions(+), 119 deletions(-) diff --git a/VAMobile/e2e/tests/utils.ts b/VAMobile/e2e/tests/utils.ts index 564ed270373..7754cbcdd3d 100644 --- a/VAMobile/e2e/tests/utils.ts +++ b/VAMobile/e2e/tests/utils.ts @@ -147,9 +147,9 @@ export const CommonE2eIdConstants = { } /** Logs into demo mode. -* @param skipOnboarding: Boolean value that defaults to true. Set this to false if you want the detox test to view the onboarding carasoul on login -* @param pushNotifications: Boolean value that tells the detox tests whether to turn on/off push notifications -* */ + * @param skipOnboarding: Boolean value that defaults to true. Set this to false if you want the detox test to view the onboarding carasoul on login + * @param pushNotifications: Boolean value that tells the detox tests whether to turn on/off push notifications + * */ export async function loginToDemoMode(skipOnboarding = true, pushNotifications?: boolean) { try { await waitFor(element(by.id(CommonE2eIdConstants.VA_LOGO_ICON_ID))) @@ -460,10 +460,10 @@ export async function backButton(backButtonName: string) { } /** Enables the availibility banner. -* @param AFFeature: Name of the AF waygate. -* @param AFUseCase: Name of the AF type. -* @param AFAppUpdate: Boolean value that tells the script whether to enable the update now button or not -* */ + * @param AFFeature: Name of the AF waygate. + * @param AFUseCase: Name of the AF type. + * @param AFAppUpdate: Boolean value that tells the script whether to enable the update now button or not + * */ export async function enableAF(AFFeature, AFUseCase, AFAppUpdate = false) { await device.launchApp({ newInstance: true, permissions: { notifications: 'YES' } }) await loginToDemoMode() @@ -543,11 +543,11 @@ export async function enableAF(AFFeature, AFUseCase, AFAppUpdate = false) { } /** Disables the availibility banner. -* @param featureNavigationArray: Array that tells the AF script how to navigate to the feature -* @param AFFeature: Name of the AF waygate. -* @param AFUseCaseName: Name of the AF type. -* @param AFAppUpdate: Boolean value that tells the script whether to enable the update now button or not -* */ + * @param featureNavigationArray: Array that tells the AF script how to navigate to the feature + * @param AFFeature: Name of the AF waygate. + * @param AFUseCaseName: Name of the AF type. + * @param AFAppUpdate: Boolean value that tells the script whether to enable the update now button or not + * */ export async function disableAF(featureNavigationArray, AFFeature, AFFeatureName, AFUseCaseName) { if (AFUseCaseName === 'AllowFunction') { await element(by.id(CommonE2eIdConstants.HOME_TAB_BUTTON_ID)).tap() @@ -583,7 +583,7 @@ export async function disableAF(featureNavigationArray, AFFeature, AFFeatureName } /** Function that allows the AF script to navigate to a certain feature -* */ + * */ const navigateToFeature = async (featureNavigationArray) => { for (let j = 2; j < featureNavigationArray.length; j++) { if (featureNavigationArray[j] === 'Talk to the Veterans Crisis Line now') { @@ -652,10 +652,10 @@ const navigateToFeature = async (featureNavigationArray) => { } /** Verifies that the availibility banner is the correct type and is populated with the correct information. -* @param featureNavigationArray: Array that tells the AF script how to navigate to the feature -* @param AFUseCaseName: Name of the AF type. -* @param AFUseCaseUpgrade: Boolean value that tells the script whether to enable the update now button or not -* */ + * @param featureNavigationArray: Array that tells the AF script how to navigate to the feature + * @param AFUseCaseName: Name of the AF type. + * @param AFUseCaseUpgrade: Boolean value that tells the script whether to enable the update now button or not + * */ export async function verifyAF(featureNavigationArray, AFUseCase, AFUseCaseUpgrade = false) { let featureName if (AFUseCase !== 'AllowFunction') { @@ -718,7 +718,7 @@ export async function verifyAF(featureNavigationArray, AFUseCase, AFUseCaseUpgra /** Toggle the specified remote config feature flag * @param flagName - name of flag to toggle -* */ + * */ export async function toggleRemoteConfigFlag(flagName: string) { await loginToDemoMode() await openProfile() diff --git a/VAMobile/src/App.tsx b/VAMobile/src/App.tsx index 89350277fd9..49801b8d146 100644 --- a/VAMobile/src/App.tsx +++ b/VAMobile/src/App.tsx @@ -110,7 +110,7 @@ export type RootNavStackParamList = WebviewStackParams & { SubmitEvidenceSubtask: { claimID: string } - InAppFeedback: { task: string } + InAppFeedback: { screen: string } Tabs: undefined } diff --git a/VAMobile/src/api/appointments/cancelAppointment.tsx b/VAMobile/src/api/appointments/cancelAppointment.tsx index cdb8f223ef0..0c9a34c7c0a 100644 --- a/VAMobile/src/api/appointments/cancelAppointment.tsx +++ b/VAMobile/src/api/appointments/cancelAppointment.tsx @@ -6,7 +6,7 @@ import { DEFAULT_UPCOMING_DAYS_LIMIT, TimeFrameTypeConstants } from 'constants/a import { put } from 'store/api' import { logNonFatalErrorToFirebase } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { appointmentsKeys } from './queryKeys' @@ -30,7 +30,7 @@ const cancelAppointment = (cancelID: string) => { */ export const useCancelAppointment = () => { const queryClient = useQueryClient() - + const registerReviewEvent = useReviewEvent() return useMutation({ mutationFn: cancelAppointment, onSuccess(_, variables) { diff --git a/VAMobile/src/api/claimsAndAppeals/downloadEFolderDocument.tsx b/VAMobile/src/api/claimsAndAppeals/downloadEFolderDocument.tsx index 13a87ff846c..43acad02003 100644 --- a/VAMobile/src/api/claimsAndAppeals/downloadEFolderDocument.tsx +++ b/VAMobile/src/api/claimsAndAppeals/downloadEFolderDocument.tsx @@ -6,7 +6,7 @@ import store from 'store' import { DEMO_MODE_LETTER_ENDPOINT } from 'store/api/demo/letters' import getEnv from 'utils/env' import { downloadDemoFile, downloadFile } from 'utils/filesystem' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { claimsAndAppealsKeys } from './queryKeys' @@ -15,14 +15,18 @@ const { API_ROOT } = getEnv() /** * Fetch user E Folder Document */ -const downloadEFolderDocument = async (id: string, fileName: string): Promise => { +const downloadEFolderDocument = async ( + id: string, + fileName: string, + func: () => Promise, +): Promise => { const eFolderDocumentAPI = `${API_ROOT}/v0/efolder/documents/${id}/download?file_name=${fileName}}` const filePath = store.getState().demo.demoMode ? await downloadDemoFile(DEMO_MODE_LETTER_ENDPOINT, fileName) : await downloadFile('POST', eFolderDocumentAPI, fileName, undefined, 1) if (filePath) { - await FileViewer.open(filePath, { onDismiss: () => registerReviewEvent() }) + await FileViewer.open(filePath, { onDismiss: () => func() }) return true } } @@ -31,10 +35,11 @@ const downloadEFolderDocument = async (id: string, fileName: string): Promise { + const registerReviewEvent = useReviewEvent(false) return useQuery({ enabled: false, queryKey: [claimsAndAppealsKeys.eFolderDownloadDoc, id, fileName], - queryFn: () => downloadEFolderDocument(id, fileName), + queryFn: () => downloadEFolderDocument(id, fileName, registerReviewEvent), meta: { errorName: 'downloadEFolderDocument: Service error', }, diff --git a/VAMobile/src/api/contactInformation/deleteEmail.tsx b/VAMobile/src/api/contactInformation/deleteEmail.tsx index 64f235ccb1e..161bd464faa 100644 --- a/VAMobile/src/api/contactInformation/deleteEmail.tsx +++ b/VAMobile/src/api/contactInformation/deleteEmail.tsx @@ -5,7 +5,7 @@ import { Events, UserAnalytics } from 'constants/analytics' import { Params as APIParams, EditResponseData, del } from 'store/api' import { logAnalyticsEvent, logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { contactInformationKeys } from './queryKeys' @@ -20,6 +20,7 @@ const deleteEmail = (emailData: EmailData) => { * Returns a mutation for deleting an email */ export const useDeleteEmail = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() return useMutation({ diff --git a/VAMobile/src/api/contactInformation/saveAddress.tsx b/VAMobile/src/api/contactInformation/saveAddress.tsx index d46b837d376..c585833281a 100644 --- a/VAMobile/src/api/contactInformation/saveAddress.tsx +++ b/VAMobile/src/api/contactInformation/saveAddress.tsx @@ -5,7 +5,7 @@ import { Events, UserAnalytics } from 'constants/analytics' import { Params as APIParams, EditResponseData, post, put } from 'store/api' import { logAnalyticsEvent, logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { contactInformationKeys } from './queryKeys' import { validateAddress } from './validateAddress' @@ -32,6 +32,7 @@ export const saveAddress = async ({ addressData, revalidate }: SaveAddressParame * Returns a mutation for saving an address */ export const useSaveAddress = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() return useMutation({ diff --git a/VAMobile/src/api/contactInformation/saveEmail.tsx b/VAMobile/src/api/contactInformation/saveEmail.tsx index e6f26f6e4e2..fbd683c2ba4 100644 --- a/VAMobile/src/api/contactInformation/saveEmail.tsx +++ b/VAMobile/src/api/contactInformation/saveEmail.tsx @@ -5,7 +5,7 @@ import { Events, UserAnalytics } from 'constants/analytics' import { Params as APIParams, EditResponseData, post, put } from 'store/api' import { logAnalyticsEvent, logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { contactInformationKeys } from './queryKeys' @@ -26,6 +26,7 @@ const saveEmail = (emailData: SaveEmailData) => { * Returns a mutation for saving an email */ export const useSaveEmail = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() return useMutation({ diff --git a/VAMobile/src/api/contactInformation/savePhoneNumber.tsx b/VAMobile/src/api/contactInformation/savePhoneNumber.tsx index 0eb91a55b67..38ec6b93960 100644 --- a/VAMobile/src/api/contactInformation/savePhoneNumber.tsx +++ b/VAMobile/src/api/contactInformation/savePhoneNumber.tsx @@ -5,7 +5,7 @@ import { Events, UserAnalytics } from 'constants/analytics' import { Params as APIParams, EditResponseData, post, put } from 'store/api' import { logAnalyticsEvent, logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { contactInformationKeys } from './queryKeys' @@ -26,6 +26,7 @@ const savePhoneNumber = (phoneData: PhoneData) => { * Returns a mutation for saving a phone number */ export const useSavePhoneNumber = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() return useMutation({ diff --git a/VAMobile/src/api/decisionLetters/downloadDecisionLetter.tsx b/VAMobile/src/api/decisionLetters/downloadDecisionLetter.tsx index b707c33e2dc..11a75a69ebb 100644 --- a/VAMobile/src/api/decisionLetters/downloadDecisionLetter.tsx +++ b/VAMobile/src/api/decisionLetters/downloadDecisionLetter.tsx @@ -6,7 +6,7 @@ import store from 'store' import { DEMO_MODE_LETTER_ENDPOINT, DEMO_MODE_LETTER_NAME } from 'store/api/demo/letters' import getEnv from 'utils/env' import { downloadDemoFile, downloadFile } from 'utils/filesystem' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { decisionLettersKeys } from './queryKeys' @@ -15,14 +15,14 @@ const { API_ROOT } = getEnv() /** * Fetch user decision letter */ -const downloadDecisionLetter = async (id: string): Promise => { +const downloadDecisionLetter = async (id: string, func: () => Promise): Promise => { const escapedId = encodeURI(id) // escape chars like {} in document ID const decisionLettersEndpoint = `${API_ROOT}/v0/claims/decision-letters/${escapedId}/download` const filePath = store.getState().demo.demoMode ? await downloadDemoFile(DEMO_MODE_LETTER_ENDPOINT, DEMO_MODE_LETTER_NAME) : await downloadFile('GET', decisionLettersEndpoint, 'decision_letter.pdf', undefined, 3) if (filePath) { - await FileViewer.open(filePath, { onDismiss: () => registerReviewEvent() }) + await FileViewer.open(filePath, { onDismiss: () => func() }) return true } } @@ -31,10 +31,11 @@ const downloadDecisionLetter = async (id: string): Promise * Returns a query for a user decision letter */ export const useDownloadDecisionLetter = (id: string, options?: { enabled?: boolean }) => { + const registerReviewEvent = useReviewEvent(false) return useQuery({ ...options, queryKey: [decisionLettersKeys.downloadLetter, id], - queryFn: () => downloadDecisionLetter(id), + queryFn: () => downloadDecisionLetter(id, registerReviewEvent), meta: { errorName: 'downloadDecisionLetter: Service error', }, diff --git a/VAMobile/src/api/demographics/updateGenderIdentity.tsx b/VAMobile/src/api/demographics/updateGenderIdentity.tsx index 7dc00acb194..c4a573bc8fa 100644 --- a/VAMobile/src/api/demographics/updateGenderIdentity.tsx +++ b/VAMobile/src/api/demographics/updateGenderIdentity.tsx @@ -4,7 +4,7 @@ import { Events, UserAnalytics } from 'constants/analytics' import { put } from 'store/api' import { logAnalyticsEvent, logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { demographicsKeys } from './queryKeys' @@ -19,6 +19,7 @@ const updateGenderIdentity = (genderIdentity: string) => { * Returns a mutation for updating gender identity */ export const useUpdateGenderIdentity = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() return useMutation({ diff --git a/VAMobile/src/api/demographics/updatePreferredName.tsx b/VAMobile/src/api/demographics/updatePreferredName.tsx index ebf11905572..6ed209611a2 100644 --- a/VAMobile/src/api/demographics/updatePreferredName.tsx +++ b/VAMobile/src/api/demographics/updatePreferredName.tsx @@ -4,7 +4,7 @@ import { Events, UserAnalytics } from 'constants/analytics' import { put } from 'store/api' import { logAnalyticsEvent, logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { demographicsKeys } from './queryKeys' @@ -22,6 +22,7 @@ const updatePreferredName = (preferredName: string) => { * Returns a mutation for updating preferred name */ export const useUpdatePreferredName = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() return useMutation({ diff --git a/VAMobile/src/api/directDeposit/updateBankInfo.tsx b/VAMobile/src/api/directDeposit/updateBankInfo.tsx index 69eb5d8eaac..d0450509059 100644 --- a/VAMobile/src/api/directDeposit/updateBankInfo.tsx +++ b/VAMobile/src/api/directDeposit/updateBankInfo.tsx @@ -12,7 +12,7 @@ import { DemoState } from 'store/slices/demoSlice' import { logAnalyticsEvent, logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' import { getErrorKeys } from 'utils/errors' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { directDepositKeys } from './queryKeys' @@ -28,6 +28,7 @@ const updateBankInfo = (paymentAccountData: PaymentAccountData) => { * Returns a mutation for updating direct deposit information */ export const useUpdateBankInfo = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() const { demoMode } = useSelector((state) => state.demo) diff --git a/VAMobile/src/api/letters/downloadLetter.tsx b/VAMobile/src/api/letters/downloadLetter.tsx index be234faca9c..72a3dd2c71d 100644 --- a/VAMobile/src/api/letters/downloadLetter.tsx +++ b/VAMobile/src/api/letters/downloadLetter.tsx @@ -10,7 +10,7 @@ import { DEMO_MODE_LETTER_ENDPOINT, DEMO_MODE_LETTER_NAME } from 'store/api/demo import { logAnalyticsEvent, setAnalyticsUserProperty } from 'utils/analytics' import getEnv from 'utils/env' import { downloadDemoFile, downloadFile } from 'utils/filesystem' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { lettersKeys } from './queryKeys' @@ -22,6 +22,7 @@ const { API_ROOT } = getEnv() const downloadLetter = async ( letterType: LetterTypes, lettersOption: LettersDownloadParams, + func: () => Promise, ): Promise => { const lettersAPI = `${API_ROOT}/v0/letters/${letterType}/download` const filePath = store.getState().demo.demoMode @@ -30,7 +31,7 @@ const downloadLetter = async ( if (filePath) { logAnalyticsEvent(Events.vama_letter_download(letterType)) setAnalyticsUserProperty(UserAnalytics.vama_uses_letters()) - await FileViewer.open(filePath, { onDismiss: () => registerReviewEvent() }) + await FileViewer.open(filePath, { onDismiss: () => func() }) return true } } @@ -39,10 +40,11 @@ const downloadLetter = async ( * Returns a query for a user letter */ export const useDownloadLetter = (letterType: LetterTypes, lettersOption: LettersDownloadParams) => { + const registerReviewEvent = useReviewEvent(false) return useQuery({ enabled: false, queryKey: [lettersKeys.downloadLetter, letterType, lettersOption], - queryFn: () => downloadLetter(letterType, lettersOption), + queryFn: () => downloadLetter(letterType, lettersOption, registerReviewEvent), meta: { errorName: 'downloadLetter: Service error', }, diff --git a/VAMobile/src/api/prescriptions/requestRefills.tsx b/VAMobile/src/api/prescriptions/requestRefills.tsx index e959395f5ec..b1309d063a5 100644 --- a/VAMobile/src/api/prescriptions/requestRefills.tsx +++ b/VAMobile/src/api/prescriptions/requestRefills.tsx @@ -5,7 +5,7 @@ import { Events, UserAnalytics } from 'constants/analytics' import { put } from 'store/api' import { logAnalyticsEvent, logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { prescriptionKeys } from './queryKeys' @@ -30,6 +30,7 @@ const requestRefills = async (prescriptions: PrescriptionsList): Promise { + const registerReviewEvent = useReviewEvent(false, 'refillRequest') const queryClient = useQueryClient() return useMutation({ mutationFn: requestRefills, diff --git a/VAMobile/src/api/secureMessaging/saveDraft.tsx b/VAMobile/src/api/secureMessaging/saveDraft.tsx index 28fd2cb0da6..b99e8a8f7cc 100644 --- a/VAMobile/src/api/secureMessaging/saveDraft.tsx +++ b/VAMobile/src/api/secureMessaging/saveDraft.tsx @@ -5,7 +5,7 @@ import { UserAnalytics } from 'constants/analytics' import { Params, post, put } from 'store/api' import { logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { secureMessagingKeys } from './queryKeys' @@ -28,6 +28,7 @@ const saveDraft = ({ messageID, replyID, messageData }: SaveDraftParameters) => * Returns a mutation for saving a draft message */ export const useSaveDraft = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() return useMutation({ mutationFn: saveDraft, diff --git a/VAMobile/src/api/secureMessaging/sendMessage.tsx b/VAMobile/src/api/secureMessaging/sendMessage.tsx index 03c6bb3d3ad..4daaf22d7a7 100644 --- a/VAMobile/src/api/secureMessaging/sendMessage.tsx +++ b/VAMobile/src/api/secureMessaging/sendMessage.tsx @@ -5,7 +5,7 @@ import { UserAnalytics } from 'constants/analytics' import { Params, contentTypes, post } from 'store/api' import { logNonFatalErrorToFirebase, setAnalyticsUserProperty } from 'utils/analytics' import { isErrorObject } from 'utils/common' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { secureMessagingKeys } from './queryKeys' @@ -58,6 +58,7 @@ const sendMessage = ({ messageData, replyToID, uploads }: SendMessageParameters) * Returns a mutation for sending a message */ export const useSendMessage = () => { + const registerReviewEvent = useReviewEvent() const queryClient = useQueryClient() return useMutation({ mutationFn: sendMessage, diff --git a/VAMobile/src/constants/analytics.ts b/VAMobile/src/constants/analytics.ts index d4da9bea452..56bd896faa9 100644 --- a/VAMobile/src/constants/analytics.ts +++ b/VAMobile/src/constants/analytics.ts @@ -635,25 +635,33 @@ export const Events = { name: 'vama_gender_id_success', } }, - // vama_feedback_page_entered: (): Event => { - // return { - // name: 'vama_feedback_page_entered', - // } - // }, - // vama_feedback_page_closed: (): Event => { - // return { - // name: 'vama_feedback_page_closed', - // } - // }, - // vama_feedback_submitted: (taskCompleted: string, satisfaction: string): Event => { - // return { - // name: 'vama_feedback_submitted', - // params: { - // taskCompleted, - // satisfaction, - // }, - // } - // }, + vama_feedback_ask: (screen: string, response: boolean): Event => { + return { + name: 'vama_feedback_ask', + params: { + screen, + response, + }, + } + }, + vama_feedback_closed: (screen: string): Event => { + return { + name: 'vama_feedback_closed', + params: { + screen, + }, + } + }, + vama_feedback_submitted: (screen: string, taskCompleted: string, satisfaction: string): Event => { + return { + name: 'vama_feedback_submitted', + params: { + screen, + taskCompleted, + satisfaction, + }, + } + }, vama_givefb_close: (screenName: string): Event => { return { name: 'vama_givefb_close', diff --git a/VAMobile/src/screens/BenefitsScreen/ClaimsScreen/AppealDetailsScreen/AppealDetailsScreen.tsx b/VAMobile/src/screens/BenefitsScreen/ClaimsScreen/AppealDetailsScreen/AppealDetailsScreen.tsx index d3cc73f0a15..478e1d58f66 100644 --- a/VAMobile/src/screens/BenefitsScreen/ClaimsScreen/AppealDetailsScreen/AppealDetailsScreen.tsx +++ b/VAMobile/src/screens/BenefitsScreen/ClaimsScreen/AppealDetailsScreen/AppealDetailsScreen.tsx @@ -16,7 +16,7 @@ import { ScreenIDTypesConstants } from 'store/api/types/Screens' import { logAnalyticsEvent } from 'utils/analytics' import { formatDateMMMMDDYYYY, getFormattedTimeForTimeZone, getTranslation } from 'utils/formattingUtils' import { useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { screenContentAllowed } from 'utils/waygateConfig' import NeedHelpData from '../NeedHelpData/NeedHelpData' @@ -28,6 +28,7 @@ type AppealDetailsScreenProps = StackScreenProps { if (appeal && !loadingAppeal && !appealError) { - registerReviewEvent(true) + registerReviewEvent() } - }, [appeal, loadingAppeal, appealError]) + }, [appeal, loadingAppeal, appealError, registerReviewEvent]) const onTabChange = (tab: number) => { setSelectedTab(tab) diff --git a/VAMobile/src/screens/BenefitsScreen/ClaimsScreen/ClaimDetailsScreen/ClaimDetailsScreen.tsx b/VAMobile/src/screens/BenefitsScreen/ClaimsScreen/ClaimDetailsScreen/ClaimDetailsScreen.tsx index 167dca2a69f..d39a1d754dc 100644 --- a/VAMobile/src/screens/BenefitsScreen/ClaimsScreen/ClaimDetailsScreen/ClaimDetailsScreen.tsx +++ b/VAMobile/src/screens/BenefitsScreen/ClaimsScreen/ClaimDetailsScreen/ClaimDetailsScreen.tsx @@ -37,7 +37,7 @@ import { logAnalyticsEvent } from 'utils/analytics' import { isDisabilityCompensationClaim, numberOfItemsNeedingAttentionFromVet } from 'utils/claims' import { formatDateMMMMDDYYYY } from 'utils/formattingUtils' import { useBeforeNavBackListener, useRouteNavigation, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { featureEnabled } from 'utils/remoteConfig' import { screenContentAllowed } from 'utils/waygateConfig' @@ -64,6 +64,7 @@ function ClaimDetailsScreen({ navigation, route }: ClaimDetailsScreenProps) { const [downloadFile, setDownloadFile] = useState(false) const { claimID, claimType } = route.params + const registerReviewEvent = useReviewEvent(true) const queryClient = useQueryClient() const { data: claim, @@ -117,7 +118,7 @@ function ClaimDetailsScreen({ navigation, route }: ClaimDetailsScreenProps) { useEffect(() => { if (claim && !loadingClaim && !claimError) { - registerReviewEvent(true) + registerReviewEvent() logAnalyticsEvent( Events.vama_claim_details_open( claimID, @@ -133,7 +134,7 @@ function ClaimDetailsScreen({ navigation, route }: ClaimDetailsScreenProps) { // Keep tab switching or panel opening from triggering autoscroll setScrollIsEnabled(false) } - }, [claim, loadingClaim, claimError, claimID, attributes]) + }, [claim, loadingClaim, claimError, claimID, attributes, registerReviewEvent]) useEffect(() => { if (claimType === ClaimTypeConstants.ACTIVE && claim) { diff --git a/VAMobile/src/screens/BenefitsScreen/DisabilityRatingsScreen/DisabilityRatingsScreen.tsx b/VAMobile/src/screens/BenefitsScreen/DisabilityRatingsScreen/DisabilityRatingsScreen.tsx index 7a7c053b73e..ffb56d81bda 100644 --- a/VAMobile/src/screens/BenefitsScreen/DisabilityRatingsScreen/DisabilityRatingsScreen.tsx +++ b/VAMobile/src/screens/BenefitsScreen/DisabilityRatingsScreen/DisabilityRatingsScreen.tsx @@ -25,7 +25,7 @@ import { a11yLabelVA } from 'utils/a11yLabel' import getEnv from 'utils/env' import { capitalizeFirstLetter, displayedTextPhoneNumber } from 'utils/formattingUtils' import { useDowntime, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { screenContentAllowed } from 'utils/waygateConfig' import NoDisabilityRatings from './NoDisabilityRatings/NoDisabilityRatings' @@ -34,6 +34,7 @@ function DisabilityRatingsScreen() { const theme = useTheme() const { t } = useTranslation(NAMESPACE.COMMON) const navigation = useNavigation() + const registerReviewEvent = useReviewEvent(true) const { LINK_URL_ABOUT_DISABILITY_RATINGS } = getEnv() const { condensedMarginBetween, contentMarginBottom, gutter } = theme.dimensions @@ -57,8 +58,8 @@ function DisabilityRatingsScreen() { useFocusEffect( React.useCallback(() => { - registerReviewEvent(true) - }, []), + registerReviewEvent() + }, [registerReviewEvent]), ) const individualRatingsList: Array = ratingData?.individualRatings || [] diff --git a/VAMobile/src/screens/HealthScreen/Appointments/PastAppointments/PastAppointmentDetails.tsx b/VAMobile/src/screens/HealthScreen/Appointments/PastAppointments/PastAppointmentDetails.tsx index 0e6f7100e6d..4873e2cc04f 100644 --- a/VAMobile/src/screens/HealthScreen/Appointments/PastAppointments/PastAppointmentDetails.tsx +++ b/VAMobile/src/screens/HealthScreen/Appointments/PastAppointments/PastAppointmentDetails.tsx @@ -8,7 +8,7 @@ import { FeatureLandingTemplate } from 'components' import { Events, UserAnalytics } from 'constants/analytics' import { NAMESPACE } from 'constants/namespaces' import { logAnalyticsEvent, setAnalyticsUserProperty } from 'utils/analytics' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { AppointmentDetailsSubTypeConstants, @@ -33,6 +33,7 @@ type PastAppointmentDetailsProps = StackScreenProps { if (!getApptError && appointmentNotFound) { diff --git a/VAMobile/src/screens/HealthScreen/Pharmacy/PrescriptionDetails/PrescriptionDetails.tsx b/VAMobile/src/screens/HealthScreen/Pharmacy/PrescriptionDetails/PrescriptionDetails.tsx index 917d3301007..58200f7be57 100644 --- a/VAMobile/src/screens/HealthScreen/Pharmacy/PrescriptionDetails/PrescriptionDetails.tsx +++ b/VAMobile/src/screens/HealthScreen/Pharmacy/PrescriptionDetails/PrescriptionDetails.tsx @@ -18,7 +18,7 @@ import { a11yLabelVA } from 'utils/a11yLabel' import { logAnalyticsEvent, setAnalyticsUserProperty } from 'utils/analytics' import getEnv from 'utils/env' import { useDestructiveActionSheet, useDowntime, useExternalLink, useRouteNavigation, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { RefillTag, getDateTextAndLabel, getRxNumberTextAndLabel } from '../PrescriptionCommon' import DetailsTextSections from './DetailsTextSections' @@ -34,6 +34,7 @@ function PrescriptionDetails({ route, navigation }: PrescriptionDetailsProps) { const launchExternalLink = useExternalLink() const submitRefillAlert = useDestructiveActionSheet() const navigateTo = useRouteNavigation() + const registerReviewEvent = useReviewEvent(true) const prescriptionInDowntime = useDowntime(DowntimeFeatureTypeConstants.rx) const { t } = useTranslation(NAMESPACE.COMMON) const noneNoted = t('noneNoted') @@ -60,8 +61,8 @@ function PrescriptionDetails({ route, navigation }: PrescriptionDetailsProps) { useFocusEffect( React.useCallback(() => { setAnalyticsUserProperty(UserAnalytics.vama_uses_rx()) - registerReviewEvent(true) - }, []), + registerReviewEvent() + }, [registerReviewEvent]), ) const redirectLink = (): void => { diff --git a/VAMobile/src/screens/HealthScreen/Pharmacy/RefillTrackingDetails/RefillTrackingDetails.tsx b/VAMobile/src/screens/HealthScreen/Pharmacy/RefillTrackingDetails/RefillTrackingDetails.tsx index 271aee9dc30..2738decf43d 100644 --- a/VAMobile/src/screens/HealthScreen/Pharmacy/RefillTrackingDetails/RefillTrackingDetails.tsx +++ b/VAMobile/src/screens/HealthScreen/Pharmacy/RefillTrackingDetails/RefillTrackingDetails.tsx @@ -27,7 +27,7 @@ import { a11yLabelID, a11yLabelVA } from 'utils/a11yLabel' import { logAnalyticsEvent } from 'utils/analytics' import getEnv from 'utils/env' import { useBeforeNavBackListener, useDowntime, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { screenContentAllowed } from 'utils/waygateConfig' import { HealthStackParamList } from '../../HealthStackScreens' @@ -57,6 +57,7 @@ const getTrackingLink = (deliveryService: string): string => { function RefillTrackingDetails({ route, navigation }: RefillTrackingDetailsProps) { const { prescription } = route.params const prescriptionInDowntime = useDowntime(DowntimeFeatureTypeConstants.rx) + const registerReviewEvent = useReviewEvent(true) const { data: trackingInfo, isFetching: loadingTrackingInfo, @@ -76,8 +77,8 @@ function RefillTrackingDetails({ route, navigation }: RefillTrackingDetailsProps useFocusEffect( React.useCallback(() => { - registerReviewEvent(true) - }, []), + registerReviewEvent() + }, [registerReviewEvent]), ) const renderOtherPrescription = (otherPrescriptions: Array) => { diff --git a/VAMobile/src/screens/HealthScreen/SecureMessaging/ViewMessage/ViewMessageScreen.tsx b/VAMobile/src/screens/HealthScreen/SecureMessaging/ViewMessage/ViewMessageScreen.tsx index f4b215db10a..48b252029ae 100644 --- a/VAMobile/src/screens/HealthScreen/SecureMessaging/ViewMessage/ViewMessageScreen.tsx +++ b/VAMobile/src/screens/HealthScreen/SecureMessaging/ViewMessage/ViewMessageScreen.tsx @@ -52,7 +52,7 @@ import { GenerateFolderMessage } from 'translations/en/functions' import { logAnalyticsEvent, setAnalyticsUserProperty } from 'utils/analytics' import { showSnackBar } from 'utils/common' import { useAppDispatch, useDowntimeByScreenID, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { getfolderName } from 'utils/secureMessaging' import { screenContentAllowed } from 'utils/waygateConfig' @@ -108,6 +108,7 @@ function ViewMessageScreen({ route, navigation }: ViewMessageScreenProps) { const { t } = useTranslation(NAMESPACE.COMMON) const theme = useTheme() const dispatch = useAppDispatch() + const registerReviewEvent = useReviewEvent(true) const queryClient = useQueryClient() const { demoMode } = useSelector((state) => state.demo) @@ -168,9 +169,9 @@ function ViewMessageScreen({ route, navigation }: ViewMessageScreenProps) { useEffect(() => { if (threadFetched) { setAnalyticsUserProperty(UserAnalytics.vama_uses_sm()) - registerReviewEvent(true) + registerReviewEvent() } - }, [threadFetched]) + }, [threadFetched, registerReviewEvent]) useEffect(() => { if (messageFetched && currentFolderIdParam === SecureMessagingSystemFolderIdConstants.INBOX && currentPage) { diff --git a/VAMobile/src/screens/HomeScreen/ProfileScreen/ContactInformationScreen/ContactInformationScreen.tsx b/VAMobile/src/screens/HomeScreen/ProfileScreen/ContactInformationScreen/ContactInformationScreen.tsx index ceaa6a07e90..ce5d429750e 100644 --- a/VAMobile/src/screens/HomeScreen/ProfileScreen/ContactInformationScreen/ContactInformationScreen.tsx +++ b/VAMobile/src/screens/HomeScreen/ProfileScreen/ContactInformationScreen/ContactInformationScreen.tsx @@ -30,7 +30,7 @@ import { ScreenIDTypesConstants } from 'store/api/types' import { a11yLabelVA } from 'utils/a11yLabel' import { logAnalyticsEvent } from 'utils/analytics' import { useDowntimeByScreenID, useRouteNavigation, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { screenContentAllowed } from 'utils/waygateConfig' const getTextForPhoneData = ( @@ -134,6 +134,7 @@ function ContactInformationScreen({ navigation }: ContactInformationScreenProps) refetch: refetchContactInformation, failureCount, } = useContactInformation({ enabled: screenContentAllowed('WG_ContactInformation') }) + const registerReviewEvent = useReviewEvent(true) const contactInformationInDowntime = useDowntimeByScreenID(ScreenIDTypesConstants.CONTACT_INFORMATION_SCREEN_ID) const { contentMarginBottom, gutter, condensedMarginBetween } = theme.dimensions const [retried, setRetried] = useState(false) @@ -155,7 +156,7 @@ function ContactInformationScreen({ navigation }: ContactInformationScreenProps) const [reviewEventRegistered, setReviewEventRegistered] = useState(false) if (!reviewEventRegistered) { console.debug('REVIEW EVENT REGISTERED') - registerReviewEvent(true) + registerReviewEvent() setReviewEventRegistered(true) } diff --git a/VAMobile/src/screens/HomeScreen/ProfileScreen/PersonalInformationScreen/PersonalInformationScreen.tsx b/VAMobile/src/screens/HomeScreen/ProfileScreen/PersonalInformationScreen/PersonalInformationScreen.tsx index e55df48754e..658d0f37314 100644 --- a/VAMobile/src/screens/HomeScreen/ProfileScreen/PersonalInformationScreen/PersonalInformationScreen.tsx +++ b/VAMobile/src/screens/HomeScreen/ProfileScreen/PersonalInformationScreen/PersonalInformationScreen.tsx @@ -25,7 +25,7 @@ import { ScreenIDTypesConstants } from 'store/api/types' import { a11yLabelVA } from 'utils/a11yLabel' import { stringToTitleCase } from 'utils/formattingUtils' import { useDowntimeByScreenID, useRouteNavigation, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { featureEnabled } from 'utils/remoteConfig' import { screenContentAllowed } from 'utils/waygateConfig' @@ -62,6 +62,7 @@ function PersonalInformationScreen({ navigation }: PersonalInformationScreenProp const { gutter, condensedMarginBetween, formMarginBetween } = theme.dimensions const personalInformationInDowntime = useDowntimeByScreenID(ScreenIDTypesConstants.PERSONAL_INFORMATION_SCREEN_ID) const isScreenContentAllowed = screenContentAllowed('WG_PersonalInformation') + const registerReviewEvent = useReviewEvent(true) const { data: personalInfo, isFetching: loadingPersonalInfo, @@ -86,7 +87,7 @@ function PersonalInformationScreen({ navigation }: PersonalInformationScreenProp /** IN-App review events need to be recorded once, so we use the setState hook to guard this **/ const [reviewEventRegistered, setReviewEventRegistered] = useState(false) if (!reviewEventRegistered) { - registerReviewEvent(true) + registerReviewEvent() setReviewEventRegistered(true) } diff --git a/VAMobile/src/screens/HomeScreen/ProfileScreen/SettingsScreen/DeveloperScreen/DeveloperScreen.tsx b/VAMobile/src/screens/HomeScreen/ProfileScreen/SettingsScreen/DeveloperScreen/DeveloperScreen.tsx index 3d0c0425eb1..54e919c660f 100644 --- a/VAMobile/src/screens/HomeScreen/ProfileScreen/SettingsScreen/DeveloperScreen/DeveloperScreen.tsx +++ b/VAMobile/src/screens/HomeScreen/ProfileScreen/SettingsScreen/DeveloperScreen/DeveloperScreen.tsx @@ -176,7 +176,6 @@ function DeveloperScreen({ navigation }: DeveloperScreenSettingsScreenProps) { ] const onFeedback = () => { - //logAnalyticsEvent(Events.vama_feedback_page_entered()) inAppFeedback('Developer') } diff --git a/VAMobile/src/screens/HomeScreen/ProfileScreen/SettingsScreen/InAppFeedbackScreen/InAppFeedbackScreen.tsx b/VAMobile/src/screens/HomeScreen/ProfileScreen/SettingsScreen/InAppFeedbackScreen/InAppFeedbackScreen.tsx index a0697269668..6e79068807b 100644 --- a/VAMobile/src/screens/HomeScreen/ProfileScreen/SettingsScreen/InAppFeedbackScreen/InAppFeedbackScreen.tsx +++ b/VAMobile/src/screens/HomeScreen/ProfileScreen/SettingsScreen/InAppFeedbackScreen/InAppFeedbackScreen.tsx @@ -8,29 +8,36 @@ import { Button } from '@department-of-veterans-affairs/mobile-component-library import { RootNavStackParamList } from 'App' import { BorderColorVariant, Box, LargePanel, RadioGroup, RadioGroupProps, TextView, VATextInput } from 'components' +import { Events } from 'constants/analytics' import { NAMESPACE } from 'constants/namespaces' -import { checkStringForPII } from 'utils/common' +import { logAnalyticsEvent } from 'utils/analytics' +import { checkStringForPII, showSnackBar } from 'utils/common' import getEnv from 'utils/env' -import { useExternalLink, useTheme } from 'utils/hooks' +import { useAppDispatch, useBeforeNavBackListener, useExternalLink, useTheme } from 'utils/hooks' const { LINK_URL_OMB_PAGE } = getEnv() type InAppFeedbackScreenProps = StackScreenProps -function InAppFeedbackScreen({ navigation }: InAppFeedbackScreenProps) { +function InAppFeedbackScreen({ navigation, route }: InAppFeedbackScreenProps) { const { t } = useTranslation(NAMESPACE.COMMON) const theme = useTheme() const [satisfaction, setSatisfaction] = useState('') const [task, setTaskOverride] = useState('') + const dispatch = useAppDispatch() + const { screen } = route.params + let submittedCheck = false const launchExternalLink = useExternalLink() - // useBeforeNavBackListener(navigation, () => { - // logAnalyticsEvent(Events.vama_feedback_page_closed()) - // }) + useBeforeNavBackListener(navigation, () => { + if (submittedCheck === true) { + return + } + logAnalyticsEvent(Events.vama_feedback_closed(screen)) + }) const onSubmit = (): void => { const { found, newText } = checkStringForPII(task) - // logAnalyticsEvent(Events.vama_feedback_submitted(taskCompleted, satisfaction)) if (found) { Alert.alert(t('inAppFeedback.personalInfo.title'), t('inAppFeedback.personalInfo.body'), [ { @@ -40,14 +47,19 @@ function InAppFeedbackScreen({ navigation }: InAppFeedbackScreenProps) { { text: t('inAppFeedback.personalInfo.submit'), onPress: () => { - setTaskOverride(newText) + logAnalyticsEvent(Events.vama_feedback_submitted(screen, newText, satisfaction)) + submittedCheck = true navigation.goBack() + showSnackBar(t('inAppFeedback.snackbar.success'), dispatch, undefined, true, false, false) }, style: 'default', }, ]) } else { + logAnalyticsEvent(Events.vama_feedback_submitted(screen, task, satisfaction)) + submittedCheck = true navigation.goBack() + showSnackBar(t('inAppFeedback.snackbar.success'), dispatch, undefined, true, false, false) } } diff --git a/VAMobile/src/screens/HomeScreen/VeteranStatusScreen/VeteranStatusScreen.tsx b/VAMobile/src/screens/HomeScreen/VeteranStatusScreen/VeteranStatusScreen.tsx index 2fcaacdae2c..496e2606237 100644 --- a/VAMobile/src/screens/HomeScreen/VeteranStatusScreen/VeteranStatusScreen.tsx +++ b/VAMobile/src/screens/HomeScreen/VeteranStatusScreen/VeteranStatusScreen.tsx @@ -24,7 +24,7 @@ import { import { NAMESPACE } from 'constants/namespaces' import { HomeStackParamList } from 'screens/HomeScreen/HomeStackScreens' import { useBeforeNavBackListener, useOrientation, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { displayedTextPhoneNumber } from '../../../utils/formattingUtils' @@ -39,6 +39,7 @@ function VeteranStatusScreen({ navigation }: VeteranStatusScreenProps) { const { data: ratingData } = useDisabilityRating() const { data: userAuthorizedServices } = useAuthorizedServices() const { data: personalInfo } = usePersonalInformation() + const registerReviewEvent = useReviewEvent(true) const accessToMilitaryInfo = userAuthorizedServices?.militaryServiceHistory && serviceHistory.length > 0 const theme = useTheme() const { t } = useTranslation(NAMESPACE.COMMON) @@ -50,7 +51,7 @@ function VeteranStatusScreen({ navigation }: VeteranStatusScreenProps) { : undefined useBeforeNavBackListener(navigation, () => { - registerReviewEvent(true) + registerReviewEvent() }) const getPeriodOfService: React.ReactNode = map(serviceHistory, (service: ServiceData) => { diff --git a/VAMobile/src/screens/PaymentsScreen/PaymentHistory/PaymentDetailsScreen/PaymentDetailsScreen.tsx b/VAMobile/src/screens/PaymentsScreen/PaymentHistory/PaymentDetailsScreen/PaymentDetailsScreen.tsx index e3febaf63e6..e5955b5b704 100644 --- a/VAMobile/src/screens/PaymentsScreen/PaymentHistory/PaymentDetailsScreen/PaymentDetailsScreen.tsx +++ b/VAMobile/src/screens/PaymentsScreen/PaymentHistory/PaymentDetailsScreen/PaymentDetailsScreen.tsx @@ -9,7 +9,7 @@ import { DIRECT_DEPOSIT } from 'constants/common' import { NAMESPACE } from 'constants/namespaces' import { formatDateUtc } from 'utils/formattingUtils' import { useRouteNavigation, useTheme } from 'utils/hooks' -import { registerReviewEvent } from 'utils/inAppReviews' +import { useReviewEvent } from 'utils/inAppReviews' import { PaymentsStackParamList } from '../../PaymentsStackScreens' @@ -20,11 +20,12 @@ function PaymentDetailsScreen({ navigation, route }: PaymentDetailsScreenProps) const { t } = useTranslation(NAMESPACE.COMMON) const theme = useTheme() const navigateTo = useRouteNavigation() + const registerReviewEvent = useReviewEvent(true) useFocusEffect( React.useCallback(() => { - registerReviewEvent(true) - }, []), + registerReviewEvent() + }, [registerReviewEvent]), ) const placeHolder = t('noneNoted') diff --git a/VAMobile/src/translations/en/common.json b/VAMobile/src/translations/en/common.json index cc7ce1f4c0c..6b0298d316b 100644 --- a/VAMobile/src/translations/en/common.json +++ b/VAMobile/src/translations/en/common.json @@ -847,6 +847,7 @@ "inAppFeedback.personalInfo.body": "You can still submit your feedback. But we recommend deleting any personal information you included.", "inAppFeedback.personalInfo.edit": "Edit feedback", "inAppFeedback.personalInfo.submit": "Submit anyway", + "inAppFeedback.snackbar.success": "Feedback sent", "inAppRecruitment.contracts": "VA contracts: 36C10B22C0011 & 36C10X18C0061", "inAppRecruitment.goToQuestionnaire": "Go to questionnaire", "inAppRecruitment.goToQuestionnaire.loading": "Loading questionnaire...", diff --git a/VAMobile/src/utils/hooks/index.tsx b/VAMobile/src/utils/hooks/index.tsx index 52666d665f3..75ef40da0f2 100644 --- a/VAMobile/src/utils/hooks/index.tsx +++ b/VAMobile/src/utils/hooks/index.tsx @@ -223,10 +223,13 @@ export function useGiveFeedback(): (task: string) => void { return (task: string) => { const onOKPress = () => { + logAnalyticsEvent(Events.vama_feedback_ask(task, true)) navigateTo('InAppFeedback', { task }) } - const onCancelPress = () => {} + const onCancelPress = () => { + logAnalyticsEvent(Events.vama_feedback_ask(task, false)) + } Alert.alert(t('inAppFeedback.popup.title'), t('inAppFeedback.popup.body'), [ { diff --git a/VAMobile/src/utils/inAppReviews.tsx b/VAMobile/src/utils/inAppReviews.tsx index 1d7515a2b18..bcc852eba67 100644 --- a/VAMobile/src/utils/inAppReviews.tsx +++ b/VAMobile/src/utils/inAppReviews.tsx @@ -6,34 +6,70 @@ import { Events } from 'constants/analytics' import { logAnalyticsEvent } from './analytics' import { getVersionName } from './deviceData' +import { useGiveFeedback } from './hooks' import { featureEnabled } from './remoteConfig' import { requestReview } from './rnReviews' export const STORAGE_REVIEW_EVENT_KEY = '@review_event' +export const STORAGE_FEEDBACK_EVENT_KEY = '@feedback_event_' export const STORAGE_LAST_REVIEW_PROMPT_DATE_MILLIS = '@last_review_date' +export const STORAGE_LAST_FEEDBACK_PROMPT_DATE_MILLIS = '@last_feedback_date' export const STORAGE_LAST_REVIEW_VERSION = '@last_review_version' export const IN_APP_REVIEW_INTERVAL_DAYS = 122 +export const IN_APP_FEEDBACK_INTERVAL_DAYS = 30 export const IN_APP_REVIEW_ACTIONS_THRESHOLD = 7 +export const IN_APP_FEEDBACK_ACTIONS_THRESHOLD = 3 -export const registerReviewEvent = async (screenView?: boolean): Promise => { - if (!featureEnabled('inAppReview')) return - const prev = await AsyncStorage.getItem(STORAGE_REVIEW_EVENT_KEY) - const total = prev ? parseInt(prev, 10) + 1 : 1 - await AsyncStorage.setItem(STORAGE_REVIEW_EVENT_KEY, `${total}`) - const versionName = await getVersionName() - if (!screenView && total >= IN_APP_REVIEW_ACTIONS_THRESHOLD) { - const lastReview = await AsyncStorage.getItem(STORAGE_LAST_REVIEW_PROMPT_DATE_MILLIS) - if (!lastReview) { - await callReviewAPI(versionName) - } else { - const days = DateTime.fromMillis(parseInt(lastReview, 10)).diffNow('days').days - const lastReviewVersion = await AsyncStorage.getItem(STORAGE_LAST_REVIEW_VERSION) - - if (days > IN_APP_REVIEW_INTERVAL_DAYS && lastReviewVersion !== versionName) { +export const useReviewEvent = (screenView?: boolean, feedbackScreen?: string): (() => Promise) => { + const inAppFeedback = useGiveFeedback() + + const reviewEvent = async () => { + if (!featureEnabled('inAppReview') && !featureEnabled('inAppFeedback')) return + //Checked for feedbackScreen triggers first. + if (featureEnabled('inAppFeedback') && feedbackScreen) { + const feedbackKey = STORAGE_FEEDBACK_EVENT_KEY.concat(feedbackScreen) + const feedbackCount = await AsyncStorage.getItem(STORAGE_FEEDBACK_EVENT_KEY.concat(feedbackScreen)) + const totalFeedback = feedbackCount ? parseInt(feedbackCount, 10) + 1 : 1 + //always increment the count when a feedback screen is registered + await AsyncStorage.setItem(feedbackKey, `${totalFeedback}`) + //check if this register would prompt for feedback + if (totalFeedback >= IN_APP_FEEDBACK_ACTIONS_THRESHOLD) { + //this date does not need to be feedbackScreen specific based on AC's: + //'Do not display feedback if user has submitted feedback for any feature within the past 30 days' + const lastFeedback = await AsyncStorage.getItem(STORAGE_LAST_FEEDBACK_PROMPT_DATE_MILLIS) + //doesn't prompt for feedback if feedback has been given in past 30 days. If prompt for feedback, return and skip potential in app review + if ( + (lastFeedback && + DateTime.fromMillis(parseInt(lastFeedback, 10)).diffNow('days').days > IN_APP_FEEDBACK_INTERVAL_DAYS) || + !lastFeedback + ) { + inAppFeedback(feedbackScreen) + await AsyncStorage.setItem(feedbackKey, '0') + await AsyncStorage.setItem(STORAGE_LAST_FEEDBACK_PROMPT_DATE_MILLIS, `${DateTime.now().millisecond}`) + return + } + } + } + const prev = await AsyncStorage.getItem(STORAGE_REVIEW_EVENT_KEY) + const total = prev ? parseInt(prev, 10) + 1 : 1 + await AsyncStorage.setItem(STORAGE_REVIEW_EVENT_KEY, `${total}`) + const versionName = await getVersionName() + if (!screenView && total >= IN_APP_REVIEW_ACTIONS_THRESHOLD) { + const lastReview = await AsyncStorage.getItem(STORAGE_LAST_REVIEW_PROMPT_DATE_MILLIS) + if (!lastReview) { await callReviewAPI(versionName) + } else { + const days = DateTime.fromMillis(parseInt(lastReview, 10)).diffNow('days').days + const lastReviewVersion = await AsyncStorage.getItem(STORAGE_LAST_REVIEW_VERSION) + + if (days > IN_APP_REVIEW_INTERVAL_DAYS && lastReviewVersion !== versionName) { + await callReviewAPI(versionName) + } } } } + + return reviewEvent } const callReviewAPI = async (versionName: string): Promise => { diff --git a/VAMobile/src/utils/remoteConfig.test.ts b/VAMobile/src/utils/remoteConfig.test.ts index f80de88dc3c..0ebfc5c62b9 100644 --- a/VAMobile/src/utils/remoteConfig.test.ts +++ b/VAMobile/src/utils/remoteConfig.test.ts @@ -23,6 +23,7 @@ const mockOverrides = { decisionLettersWaygate: false, haptics: false, homeScreenPrefetch: false, + inAppFeedback: false, inAppRecruitment: false, inAppReview: true, inAppUpdates: false, diff --git a/VAMobile/src/utils/remoteConfig.ts b/VAMobile/src/utils/remoteConfig.ts index 98e6f7308b4..bf8127e2f6a 100644 --- a/VAMobile/src/utils/remoteConfig.ts +++ b/VAMobile/src/utils/remoteConfig.ts @@ -22,6 +22,7 @@ export type FeatureToggleType = | 'haptics' | 'homeScreenPrefetch' | 'inAppRecruitment' + | 'inAppFeedback' | 'inAppReview' | 'inAppUpdates' | 'patientCheckIn' @@ -41,6 +42,7 @@ type FeatureToggleValues = { haptics: boolean homeScreenPrefetch: boolean inAppRecruitment: boolean + inAppFeedback: boolean inAppReview: boolean inAppUpdates: boolean patientCheckIn: boolean @@ -61,6 +63,7 @@ export const defaults: FeatureToggleValues = { haptics: true, homeScreenPrefetch: true, inAppRecruitment: false, + inAppFeedback: false, inAppReview: true, inAppUpdates: true, patientCheckIn: false,