diff --git a/ts/components/dialog/SessionCTA.tsx b/ts/components/dialog/SessionCTA.tsx index 808fd7993..97fd855d5 100644 --- a/ts/components/dialog/SessionCTA.tsx +++ b/ts/components/dialog/SessionCTA.tsx @@ -417,7 +417,7 @@ export const useShowSessionCTACbWithVariant = () => { }; }; -export async function handleTriggeredProCTAs(dispatch: Dispatch) { +export async function handleTriggeredCTAs(dispatch: Dispatch, fromAppStart: boolean) { const proAvailable = getFeatureFlag('proAvailable'); if (Storage.get(SettingsKey.proExpiringSoonCTA)) { @@ -441,6 +441,10 @@ export async function handleTriggeredProCTAs(dispatch: Dispatch) { ); await Storage.put(SettingsKey.proExpiredCTA, false); } else { + if (!fromAppStart) { + // we only want to show the DonateCTA when the app starts, if needed + return; + } const dbCreationTimestampMs = await Data.getDBCreationTimestampMs(); if (dbCreationTimestampMs && dbCreationTimestampMs + 7 * DURATION.DAYS < Date.now()) { const donateInteractions = getUrlInteractionsForUrl(APP_URL.DONATE); diff --git a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx index 64ae50e84..aa10f3304 100644 --- a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx +++ b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx @@ -6,7 +6,7 @@ import { type UserSettingsPage, } from '../../../../state/ducks/modalDialog'; import { assertUnreachable } from '../../../../types/sqlSharedTypes'; -import { handleTriggeredProCTAs } from '../../SessionCTA'; +import { handleTriggeredCTAs } from '../../SessionCTA'; import { getFeatureFlag } from '../../../../state/ducks/types/releasedFeaturesReduxTypes'; export function useUserSettingsTitle(page: UserSettingsModalState | undefined) { @@ -82,7 +82,7 @@ export function useUserSettingsCloseAction(props: UserSettingsModalState) { return () => { dispatch(userSettingsModal(null)); if (getFeatureFlag('proAvailable')) { - void handleTriggeredProCTAs(dispatch); + void handleTriggeredCTAs(dispatch, false); } props.afterCloseAction?.(); }; diff --git a/ts/session/apis/snode_api/swarmPolling.ts b/ts/session/apis/snode_api/swarmPolling.ts index c11121cf5..4748be743 100644 --- a/ts/session/apis/snode_api/swarmPolling.ts +++ b/ts/session/apis/snode_api/swarmPolling.ts @@ -55,6 +55,7 @@ import { getCachedUserConfig, UserConfigWrapperActions, } from '../../../webworker/workers/browser/libsession/libsession_worker_userconfig_interface'; +import { isTestIntegration } from '../../../shared/env_vars'; const minMsgCountShouldRetry = 95; /** @@ -969,6 +970,11 @@ export class SwarmPolling { window.log.info( `[onboarding] about to pollOnceForOurDisplayName of ${ed25519Str(pubkey.key)} from snode: ${ed25519Str(toPollFrom.pubkey_ed25519)} namespaces: ${[SnodeNamespaces.UserProfile]} ` ); + if (isTestIntegration()) { + // During integration tests, often deviceA might not have pushed to the swarm the userConfig that deviceB is looking for. + // To deal with, this, we wait a bit here before trying to fetch the userConfig. + await sleepFor(2000); + } const retrieved = await SnodeAPIRetrieve.retrieveNextMessagesNoRetries( toPollFrom, pubkey.key, @@ -983,13 +989,17 @@ export class SwarmPolling { `[onboarding] pollOnceForOurDisplayName of ${ed25519Str(pubkey.key)} from snode: ${ed25519Str(toPollFrom.pubkey_ed25519)} namespaces: ${[SnodeNamespaces.UserProfile]} returned: ${retrieved?.length}` ); if (!retrieved?.length) { + // Note: always print something so we know if the polling is hanging + window.log.info( + `[onboarding] pollOnceForOurDisplayName of ${ed25519Str(pubkey.key)} from snode: ${ed25519Str(toPollFrom.pubkey_ed25519)} namespaces: ${[SnodeNamespaces.UserProfile]} returned: ${retrieved?.length}` + ); + /** * Sometimes, a snode is out of sync with its swarm but still replies with what he thinks is the swarm's content. * When that happens, we can get a "no display name" error, as indeed, that snode didn't have a config message on user profile. * To fix this, we've added a check over all of the snodes of our swarm, and we pick the first one that reports having a config message on user profile. * This won't take care of the case where a snode has a message with an empty display name, but it's not the root issue that this was added for. */ - throw new Error( `pollOnceForOurDisplayName of ${ed25519Str(pubkey.key)} from snode: ${ed25519Str(toPollFrom.pubkey_ed25519)} no results from user profile` ); diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 72d2b3fe2..fe2065061 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -33,7 +33,7 @@ import { sectionActions } from './section'; import { ed25519Str } from '../../session/utils/String'; import { UserUtils } from '../../session/utils'; import type { ProMessageFeature } from '../../models/proMessageFeature'; -import { handleTriggeredProCTAs } from '../../components/dialog/SessionCTA'; +import { handleTriggeredCTAs } from '../../components/dialog/SessionCTA'; import { getFeatureFlag } from './types/releasedFeaturesReduxTypes'; export type MessageModelPropsWithoutConvoProps = { @@ -1148,7 +1148,7 @@ export async function openConversationWithMessages(args: { if (window.inboxStore) { if (getFeatureFlag('proAvailable')) { - await handleTriggeredProCTAs(window.inboxStore.dispatch); + await handleTriggeredCTAs(window.inboxStore.dispatch, false); } } } diff --git a/ts/state/startup.ts b/ts/state/startup.ts index 93a8b6b7c..a7732d52e 100644 --- a/ts/state/startup.ts +++ b/ts/state/startup.ts @@ -29,7 +29,7 @@ import { initialNetworkDataState, networkDataActions } from './ducks/networkData import { initialProBackendDataState, proBackendDataActions } from './ducks/proBackendData'; import { MessageQueue } from '../session/sending'; import { AvatarMigrate } from '../session/utils/job_runners/jobs/AvatarMigrateJob'; -import { handleTriggeredProCTAs } from '../components/dialog/SessionCTA'; +import { handleTriggeredCTAs } from '../components/dialog/SessionCTA'; import { UserSync } from '../session/utils/job_runners/jobs/UserSyncJob'; import { forceSyncConfigurationNowIfNeeded } from '../session/utils/sync/syncUtils'; import { SnodePool } from '../session/apis/snode_api/snodePool'; @@ -166,18 +166,19 @@ export const doAppStartUp = async () => { proBackendDataActions.refreshGetProDetailsFromProBackend({}) as any ); if (window.inboxStore) { - if (getDataFeatureFlag('useLocalDevNet') && isTestIntegration()) { - /** - * When running on the local dev net (during the regression tests), the network is too fast - * and we show the DonateCTA before we got the time to grab the recovery phrase. - * This sleepFor is there to give some time so we can grab the recovery phrase. - * The regression test this is about is `Donate CTA, DB age >= 7 days` - */ - await sleepFor(1000); - } - if (window.inboxStore?.dispatch) { - void handleTriggeredProCTAs(window.inboxStore.dispatch); - } + const delayedTimeout = getDataFeatureFlag('useLocalDevNet') && isTestIntegration() ? 2000 : 0; + /** + * When running on the local dev net (during the regression tests), the network is too fast + * and we show the DonateCTA before we got the time to grab the recovery phrase. + * This sleepFor is there to give some time so we can grab the recovery phrase. + * The regression test this is about is `Donate CTA, DB age >= 7 days` + */ + // eslint-disable-next-line more/no-then + void sleepFor(delayedTimeout).then(() => { + if (window.inboxStore?.dispatch) { + void handleTriggeredCTAs(window.inboxStore.dispatch, true); + } + }); } // we want to (try) to fetch from the revocation server before we process // incoming messages, as some might have a pro proof that has been revoked