Skip to content

Commit

Permalink
Merge pull request #50516 from Expensify/dsilva_fullstoryStartRecordi…
Browse files Browse the repository at this point in the history
…ngSettings

Change Fullstory recording start conditions
  • Loading branch information
AndrewGable authored Oct 16, 2024
2 parents bac04c5 + 99f6ecf commit 286212c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 103 deletions.
61 changes: 17 additions & 44 deletions src/Expensify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, use
import type {NativeEventSubscription} from 'react-native';
import {AppState, Linking, NativeModules, Platform} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import Onyx, {useOnyx, withOnyx} from 'react-native-onyx';
import Onyx, {useOnyx} from 'react-native-onyx';
import ConfirmModal from './components/ConfirmModal';
import DeeplinkWrapper from './components/DeeplinkWrapper';
import EmojiPicker from './components/EmojiPicker/EmojiPicker';
Expand Down Expand Up @@ -55,7 +55,7 @@ Onyx.registerLogger(({level, message}) => {
}
});

type ExpensifyOnyxProps = {
type ExpensifyProps = {
/** Whether the app is waiting for the server's response to determine if a room is public */
isCheckingPublicRoom: OnyxEntry<boolean>;

Expand All @@ -77,18 +77,7 @@ type ExpensifyOnyxProps = {
/** Last visited path in the app */
lastVisitedPath: OnyxEntry<string | undefined>;
};

type ExpensifyProps = ExpensifyOnyxProps;

function Expensify({
isCheckingPublicRoom = true,
updateAvailable,
isSidebarLoaded = false,
screenShareRequest,
updateRequired = false,
focusModeNotification = false,
lastVisitedPath,
}: ExpensifyProps) {
function Expensify() {
const appStateChangeListener = useRef<NativeEventSubscription | null>(null);
const [isNavigationReady, setIsNavigationReady] = useState(false);
const [isOnyxMigrated, setIsOnyxMigrated] = useState(false);
Expand All @@ -98,7 +87,15 @@ function Expensify({
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const [session] = useOnyx(ONYXKEYS.SESSION);
const [lastRoute] = useOnyx(ONYXKEYS.LAST_ROUTE);
const [userMetadata] = useOnyx(ONYXKEYS.USER_METADATA);
const [shouldShowRequire2FAModal, setShouldShowRequire2FAModal] = useState(false);
const [isCheckingPublicRoom] = useOnyx(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM);
const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE);
const [updateRequired] = useOnyx(ONYXKEYS.UPDATE_REQUIRED);
const [isSidebarLoaded] = useOnyx(ONYXKEYS.IS_SIDEBAR_LOADED);
const [screenShareRequest] = useOnyx(ONYXKEYS.SCREEN_SHARE_REQUEST);
const [focusModeNotification] = useOnyx(ONYXKEYS.FOCUS_MODE_NOTIFICATION);
const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH);

useEffect(() => {
if (!account?.needsTwoFactorAuthSetup || account.requiresTwoFactorAuth) {
Expand Down Expand Up @@ -148,15 +145,17 @@ function Expensify({
// Initialize this client as being an active client
ActiveClientManager.init();

// Initialize Fullstory lib
FS.init();

// Used for the offline indicator appearing when someone is offline
const unsubscribeNetInfo = NetworkConnection.subscribeToNetInfo();

return unsubscribeNetInfo;
}, []);

useEffect(() => {
// Initialize Fullstory lib
FS.init(userMetadata);
}, [userMetadata]);

// Log the platform and config to debug .env issues
useEffect(() => {
Log.info('App launched', false, {Platform, CONFIG});
Expand Down Expand Up @@ -304,30 +303,4 @@ function Expensify({

Expensify.displayName = 'Expensify';

export default withOnyx<ExpensifyProps, ExpensifyOnyxProps>({
isCheckingPublicRoom: {
key: ONYXKEYS.IS_CHECKING_PUBLIC_ROOM,
initWithStoredValues: false,
},
updateAvailable: {
key: ONYXKEYS.UPDATE_AVAILABLE,
initWithStoredValues: false,
},
updateRequired: {
key: ONYXKEYS.UPDATE_REQUIRED,
initWithStoredValues: false,
},
isSidebarLoaded: {
key: ONYXKEYS.IS_SIDEBAR_LOADED,
},
screenShareRequest: {
key: ONYXKEYS.SCREEN_SHARE_REQUEST,
},
focusModeNotification: {
key: ONYXKEYS.FOCUS_MODE_NOTIFICATION,
initWithStoredValues: false,
},
lastVisitedPath: {
key: ONYXKEYS.LAST_VISITED_PATH,
},
})(Expensify);
export default Expensify;
53 changes: 22 additions & 31 deletions src/libs/Fullstory/index.native.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import FullStory, {FSPage} from '@fullstory/react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import CONST from '@src/CONST';
import * as Environment from '@src/libs/Environment/Environment';
import ONYXKEYS from '@src/ONYXKEYS';
import type {UserMetadata} from '@src/types/onyx';

/**
Expand All @@ -14,18 +12,8 @@ const FS = {
/**
* Initializes FullStory
*/
init: () => {
Environment.getEnvironment().then((envName: string) => {
// We only want to start fullstory if the app is running in production
// Since we don't use it in other environments, it is also disabled in build.gradle to speed up Android build times
// See https://github.com/Expensify/App/pull/50206 for more information
if (envName !== CONST.ENVIRONMENT.PRODUCTION) {
return;
}
FullStory.restart();
const [session] = useOnyx(ONYXKEYS.USER_METADATA);
FS.fsIdentify(session);
});
init: (value: OnyxEntry<UserMetadata>) => {
FS.consentAndIdentify(value);
},

/**
Expand All @@ -42,32 +30,35 @@ const FS = {
* Initializes the FullStory metadata with the provided metadata information.
*/
consentAndIdentify: (value: OnyxEntry<UserMetadata>) => {
// On the first subscribe for UserMetadta, this function will be called. We need
// to confirm that we actually have any value here before proceeding.
if (!value?.accountID) {
return;
}
try {
// We only use FullStory in production environment
FullStory.consent(true);
FS.fsIdentify(value);
// We only use FullStory in production environment. We need to check this here
// after the init function since this function is also called on updates for
// UserMetadata onyx key.
Environment.getEnvironment().then((envName: string) => {
if (envName !== CONST.ENVIRONMENT.PRODUCTION) {
return;
}
FullStory.restart();
FullStory.consent(true);
FS.fsIdentify(value, envName);
});
} catch (e) {
// error handler
}
},

/**
* Sets the FullStory user identity based on the provided metadata information.
* If the metadata is null or the email is 'undefined', the user identity is anonymized.
* If the metadata contains an accountID, the user identity is defined with it.
*/
fsIdentify: (metadata: OnyxEntry<UserMetadata>) => {
if (!metadata?.accountID) {
// anonymize FullStory user identity metadata
FullStory.anonymize();
} else {
Environment.getEnvironment().then((envName: string) => {
// define FullStory user identity
const localMetadata = metadata;
localMetadata.environment = envName;
FullStory.identify(String(localMetadata.accountID), localMetadata);
});
}
fsIdentify: (metadata: UserMetadata, envName: string) => {
const localMetadata = metadata;
localMetadata.environment = envName;
FullStory.identify(String(localMetadata.accountID), localMetadata);
},
};

Expand Down
48 changes: 20 additions & 28 deletions src/libs/Fullstory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,11 @@ const FS = {
*/
onReady: () =>
new Promise((resolve) => {
Environment.getEnvironment().then((envName: string) => {
if (CONST.ENVIRONMENT.PRODUCTION !== envName) {
return;
}
// Initialised via HEAD snippet
if (!isInitialized()) {
init({orgId: ''}, resolve);
} else {
FullStory('observe', {type: 'start', callback: resolve});
}
});
if (!isInitialized()) {
init({orgId: ''}, resolve);
} else {
FullStory('observe', {type: 'start', callback: resolve});
}
}),

/**
Expand All @@ -56,18 +50,21 @@ const FS = {
* Initializes the FullStory metadata with the provided metadata information.
*/
consentAndIdentify: (value: OnyxEntry<UserMetadata>) => {
// On the first subscribe for UserMetadata, this function will be called. We need
// to confirm that we actually have any value here before proceeding.
if (!value?.accountID) {
return;
}
try {
Environment.getEnvironment().then((envName: string) => {
if (CONST.ENVIRONMENT.PRODUCTION !== envName) {
return;
}
FS.onReady().then(() => {
FS.consent(true);
if (value) {
const localMetadata = value;
localMetadata.environment = envName;
FS.fsIdentify(localMetadata);
}
const localMetadata = value;
localMetadata.environment = envName;
FS.fsIdentify(localMetadata);
});
});
} catch (e) {
Expand All @@ -80,23 +77,18 @@ const FS = {
* If the metadata does not contain an email, the user identity is anonymized.
* If the metadata contains an accountID, the user identity is defined with it.
*/
fsIdentify: (metadata: OnyxEntry<UserMetadata>) => {
if (!metadata?.accountID) {
// anonymize FullStory user identity metadata
FS.anonymize();
} else {
// define FullStory user identity
FullStory('setIdentity', {
uid: String(metadata.accountID),
properties: metadata,
});
}
fsIdentify: (metadata: UserMetadata) => {
FullStory('setIdentity', {
uid: String(metadata.accountID),
properties: metadata,
});
},

/**
* Init function, created so we're consistent with the native file
*/
init: () => {},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
init: (_value: OnyxEntry<UserMetadata>) => {},
};

export default FS;
Expand Down

0 comments on commit 286212c

Please sign in to comment.