Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0623467
Extract FS test email logic to separate function
fabioh8010 Oct 24, 2025
bb1be71
Extract common FS shouldInitialize logic
fabioh8010 Oct 24, 2025
ffbbc39
Fix type
fabioh8010 Oct 24, 2025
bbe41ce
Draft of new logic to decide if report should be masked or not
fabioh8010 Oct 24, 2025
87e44dc
Unmask money request previews
fabioh8010 Oct 24, 2025
88439c8
Merge branch 'main' into bugfix/fullstory-masking-on-chats
fabioh8010 Oct 29, 2025
a9bd90d
Merge remote-tracking branch 'origin/main' into bugfix/fullstory-mask…
fabioh8010 Oct 30, 2025
e6119a8
Fix input FS masking
fabioh8010 Oct 30, 2025
261a871
Mask the composer input if the report is masked too
fabioh8010 Oct 30, 2025
4c29e97
Mask 2FA codes
fabioh8010 Oct 31, 2025
f16a4f1
Only mask inputs in payment card form
fabioh8010 Oct 31, 2025
263f310
Fix LHN chat preview to only mask for the masked reports
fabioh8010 Oct 31, 2025
4b68dee
Merge remote-tracking branch 'origin/main' into bugfix/fullstory-mask…
fabioh8010 Oct 31, 2025
3fc344e
Merge remote-tracking branch 'origin/main' into bugfix/fullstory-mask…
fabioh8010 Nov 5, 2025
d9cd30f
Fix and improve getChatFSClass implementation
fabioh8010 Nov 5, 2025
b037369
Fix masking for company card feeds
fabioh8010 Nov 5, 2025
efc9f6e
Fix masking on USD bank account flow
fabioh8010 Nov 7, 2025
1514137
Fix masking on international bank account flow
fabioh8010 Nov 7, 2025
46b4a22
Fix masking of enable reimbursement flow
fabioh8010 Nov 7, 2025
3b9f75d
Fix masking on Wallet flow
fabioh8010 Nov 7, 2025
f7a33da
Fix masking on Wallet card details page
fabioh8010 Nov 7, 2025
a9d50c0
Fix masking on Non-USD bank flow
fabioh8010 Nov 7, 2025
8d5b46d
Merge remote-tracking branch 'origin/main' into bugfix/fullstory-mask…
fabioh8010 Nov 12, 2025
92e7352
Fix lint
fabioh8010 Nov 12, 2025
bd4dd19
Add comment about Onyx.connectWithoutView
fabioh8010 Nov 12, 2025
15040a5
TEMPORARY: Always initialize FS
fabioh8010 Nov 12, 2025
af69d3b
Merge branch 'main' into bugfix/fullstory-masking-on-chats
fabioh8010 Nov 17, 2025
4a0d827
Merge branch 'main' into bugfix/fullstory-masking-on-chats
fabioh8010 Nov 24, 2025
163a078
Revert "TEMPORARY: Always initialize FS"
fabioh8010 Nov 24, 2025
9aed55c
Merge branch 'main' into bugfix/fullstory-masking-on-chats
fabioh8010 Nov 26, 2025
981bc6c
Mask chat results on Search autocomplete list
fabioh8010 Nov 26, 2025
82ae216
Merge remote-tracking branch 'origin/main' into bugfix/fullstory-mask…
fabioh8010 Dec 1, 2025
6e100f3
Merge branch 'main' into bugfix/fullstory-masking-on-chats
fabioh8010 Dec 1, 2025
d7abc93
Merge remote-tracking branch 'origin/main' into bugfix/fullstory-mask…
fabioh8010 Dec 1, 2025
7af67d8
Merge branch 'main' into bugfix/fullstory-masking-on-chats
fabioh8010 Dec 3, 2025
0f1a7ef
Merge remote-tracking branch 'origin/main' into bugfix/fullstory-mask…
fabioh8010 Dec 3, 2025
56fb9a3
Merge branch 'main' into bugfix/fullstory-masking-on-chats
fabioh8010 Dec 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest/setupMockFullstoryLib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default function mockFSLibrary() {
getChatFSClass: jest.fn(),
init: jest.fn(),
onReady: jest.fn(),
shouldInitialize: jest.fn().mockReturnValue(false),
consent: jest.fn(),
identify: jest.fn(),
consentAndIdentify: jest.fn(),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"test:debug": "TZ=utc NODE_OPTIONS='--inspect-brk --experimental-vm-modules' jest --runInBand",
"perf-test": "NODE_OPTIONS=--experimental-vm-modules npx reassure",
"typecheck": "NODE_OPTIONS=--max_old_space_size=8192 tsc",
"lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=111 --cache --cache-location=node_modules/.cache/eslint --concurrency=auto",
"lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=112 --cache --cache-location=node_modules/.cache/eslint --concurrency=auto",
"lint-changed": "NODE_OPTIONS=--max_old_space_size=8192 ./scripts/lintChanged.sh",
"check-lazy-loading": "ts-node scripts/checkLazyLoading.ts",
"lint-watch": "npx eslint-watch --watch --changed",
Expand Down
6 changes: 5 additions & 1 deletion src/components/AddPaymentCard/PaymentCardForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ function PaymentCardForm({
submitButtonText={submitButtonText}
scrollContextEnabled
style={[styles.mh5, styles.flexGrow1]}
forwardedFSClass={CONST.FULLSTORY.CLASS.MASK}
>
<InputWrapper
InputComponent={TextInput}
Expand All @@ -275,6 +274,7 @@ function PaymentCardForm({
inputMode={CONST.INPUT_MODE.NUMERIC}
onChangeText={onChangeCardNumber}
value={cardNumber}
forwardedFSClass={CONST.FULLSTORY.CLASS.MASK}
/>
<InputWrapper
InputComponent={TextInput}
Expand All @@ -285,6 +285,7 @@ function PaymentCardForm({
role={CONST.ROLE.PRESENTATION}
containerStyles={[styles.mt5]}
spellCheck={false}
forwardedFSClass={CONST.FULLSTORY.CLASS.MASK}
/>
<View style={[styles.flexRow, styles.mt5]}>
<View style={[styles.mr2, styles.flex1]}>
Expand All @@ -301,6 +302,7 @@ function PaymentCardForm({
placeholder={translate(label.defaults.expirationDate)}
inputMode={CONST.INPUT_MODE.NUMERIC}
maxLength={5}
forwardedFSClass={CONST.FULLSTORY.CLASS.MASK}
/>
</View>
<View style={styles.flex1}>
Expand All @@ -313,6 +315,7 @@ function PaymentCardForm({
role={CONST.ROLE.PRESENTATION}
maxLength={4}
inputMode={CONST.INPUT_MODE.NUMERIC}
forwardedFSClass={CONST.FULLSTORY.CLASS.MASK}
/>
</View>
</View>
Expand All @@ -327,6 +330,7 @@ function PaymentCardForm({
maxInputLength={CONST.FORM_CHARACTER_LIMIT}
// Limit the address search only to the USA until we fully can support international debit cards
limitSearchesToCountry={CONST.COUNTRY.US}
forwardedFSClass={CONST.FULLSTORY.CLASS.MASK}
/>
</View>
)}
Expand Down
2 changes: 2 additions & 0 deletions src/components/AddressSearch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ function AddressSearch({
value,
locationBias,
caretHidden,
forwardedFSClass,
ref,
}: AddressSearchProps) {
const theme = useTheme();
Expand Down Expand Up @@ -363,6 +364,7 @@ function AddressSearch({
<View
style={styles.w100}
ref={containerRef}
fsClass={forwardedFSClass}
>
<GooglePlacesAutocomplete
disableScroll
Expand Down
3 changes: 2 additions & 1 deletion src/components/AddressSearch/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {ForwardedRef, RefObject} from 'react';
import type {BlurEvent, StyleProp, View, ViewStyle} from 'react-native';
import type {Place} from 'react-native-google-places-autocomplete';
import type {ForwardedFSClassProps} from '@libs/Fullstory/types';
import type {Country} from '@src/CONST';
import type {Address} from '@src/types/onyx/PrivatePersonalDetails';

Expand All @@ -27,7 +28,7 @@ type PredefinedPlace = Place & {
name?: string;
};

type AddressSearchProps = {
type AddressSearchProps = ForwardedFSClassProps & {
/** The ID used to uniquely identify the input in a Form */
inputID?: string;

Expand Down
86 changes: 44 additions & 42 deletions src/components/Composer/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {Ref} from 'react';
import type {StyleProp, TextInput, TextInputProps, TextInputSelectionChangeEvent, TextStyle} from 'react-native';
import type {AnimatedMarkdownTextInputRef} from '@components/RNMarkdownTextInput';
import type {ForwardedFSClassProps} from '@libs/Fullstory/types';
import type {FileObject} from '@src/types/utils/Attachment';

type TextSelection = {
Expand All @@ -14,65 +15,66 @@ type CustomSelectionChangeEvent = TextInputSelectionChangeEvent & {
positionY?: number;
};

type ComposerProps = Omit<TextInputProps, 'onClear'> & {
/** Indicate whether input is multiline */
multiline?: boolean;
type ComposerProps = Omit<TextInputProps, 'onClear'> &
ForwardedFSClassProps & {
/** Indicate whether input is multiline */
multiline?: boolean;

/** Maximum number of lines in the text input */
maxLines?: number;
/** Maximum number of lines in the text input */
maxLines?: number;

/** The default value of the comment box */
defaultValue?: string;
/** The default value of the comment box */
defaultValue?: string;

/** The value of the comment box */
value?: string;
/** The value of the comment box */
value?: string;

/**
* Callback when the input was cleared using the .clear ref method.
* The text parameter will be the value of the text that was cleared.
*/
onClear?: (text: string) => void;
/**
* Callback when the input was cleared using the .clear ref method.
* The text parameter will be the value of the text that was cleared.
*/
onClear?: (text: string) => void;

/** Callback method handle when the input is changed */
onChangeText?: (numberOfLines: string) => void;
/** Callback method handle when the input is changed */
onChangeText?: (numberOfLines: string) => void;

/** Callback method to handle pasting a file */
onPasteFile?: (files: FileObject | FileObject[]) => void;
/** Callback method to handle pasting a file */
onPasteFile?: (files: FileObject | FileObject[]) => void;

/** General styles to apply to the text input */
// eslint-disable-next-line react/forbid-prop-types
style?: StyleProp<TextStyle>;
/** General styles to apply to the text input */
// eslint-disable-next-line react/forbid-prop-types
style?: StyleProp<TextStyle>;

/** Whether or not this TextInput is disabled. */
isDisabled?: boolean;
/** Whether or not this TextInput is disabled. */
isDisabled?: boolean;

/** Set focus to this component the first time it renders.
/** Set focus to this component the first time it renders.
Override this in case you need to set focus on one field out of many, or when you want to disable autoFocus */
autoFocus?: boolean;
autoFocus?: boolean;

/** Update selection position on change */
onSelectionChange?: (event: CustomSelectionChangeEvent) => void;
/** Update selection position on change */
onSelectionChange?: (event: CustomSelectionChangeEvent) => void;

/** Selection Object */
selection?: TextSelection;
/** Selection Object */
selection?: TextSelection;

/** Should we calculate the caret position */
shouldCalculateCaretPosition?: boolean;
/** Should we calculate the caret position */
shouldCalculateCaretPosition?: boolean;

/** Function to check whether composer is covered up or not */
checkComposerVisibility?: () => boolean;
/** Function to check whether composer is covered up or not */
checkComposerVisibility?: () => boolean;

/** Whether the full composer is open */
isComposerFullSize?: boolean;
/** Whether the full composer is open */
isComposerFullSize?: boolean;

/** Should make the input only scroll inside the element avoid scroll out to parent */
shouldContainScroll?: boolean;
/** Should make the input only scroll inside the element avoid scroll out to parent */
shouldContainScroll?: boolean;

/** Indicates whether the composer is in a group policy report. Used for disabling report mentioning style in markdown input */
isGroupPolicyReport?: boolean;
/** Indicates whether the composer is in a group policy report. Used for disabling report mentioning style in markdown input */
isGroupPolicyReport?: boolean;

/** Ref exposing imperative methods on the underlying text input */
ref?: Ref<TextInput | HTMLInputElement | HTMLTextAreaElement | AnimatedMarkdownTextInputRef>;
};
/** Ref exposing imperative methods on the underlying text input */
ref?: Ref<TextInput | HTMLInputElement | HTMLTextAreaElement | AnimatedMarkdownTextInputRef>;
};

export type {TextSelection, ComposerProps, CustomSelectionChangeEvent};
2 changes: 2 additions & 0 deletions src/components/DatePicker/DatePickerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function DatePickerModal({
onSelected,
shouldCloseWhenBrowserNavigationChanged = false,
shouldPositionFromTop = false,
forwardedFSClass,
}: DatePickerProps) {
const [selectedDate, setSelectedDate] = useState(value ?? defaultValue ?? undefined);
const anchorRef = useRef<View>(null);
Expand Down Expand Up @@ -74,6 +75,7 @@ function DatePickerModal({
shouldEnableNewFocusManagement
shouldMeasureAnchorPositionFromTop={shouldPositionFromTop}
shouldSkipRemeasurement
forwardedFSClass={forwardedFSClass}
>
<CalendarPicker
minDate={minDate}
Expand Down
3 changes: 3 additions & 0 deletions src/components/DatePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function DatePicker({
formID,
autoFocus = false,
shouldHideClearButton = false,
forwardedFSClass,
ref,
}: DateInputWithPickerProps) {
const icons = useMemoizedLazyExpensifyIcons(['Calendar'] as const);
Expand Down Expand Up @@ -143,6 +144,7 @@ function DatePicker({
textInputContainerStyles={isModalVisible ? styles.borderColorFocus : {}}
shouldHideClearButton={shouldHideClearButton}
onClearInput={handleClear}
forwardedFSClass={forwardedFSClass}
/>
</View>

Expand All @@ -156,6 +158,7 @@ function DatePicker({
onClose={closeDatePicker}
anchorPosition={popoverPosition}
shouldPositionFromTop={!isInverted}
forwardedFSClass={forwardedFSClass}
/>
</>
);
Expand Down
3 changes: 2 additions & 1 deletion src/components/DatePicker/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type {ForwardedRef} from 'react';
import type PopoverWithMeasuredContentProps from '@components/PopoverWithMeasuredContent/types';
import type {BaseTextInputProps, BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';
import type {ForwardedFSClassProps} from '@libs/Fullstory/types';
import type {OnyxFormValuesMapping} from '@src/ONYXKEYS';

type DatePickerBaseProps = {
type DatePickerBaseProps = ForwardedFSClassProps & {
/**
* The datepicker supports any value that `new Date()` can parse.
* `onInputChange` would always be called with a Date (or null)
Expand Down
7 changes: 5 additions & 2 deletions src/components/LHNOptionsList/OptionRowLHN.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import DisplayNames from '@components/DisplayNames';
import Hoverable from '@components/Hoverable';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';

Check warning on line 7 in src/components/LHNOptionsList/OptionRowLHN.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'@components/Icon/Expensicons' import is restricted from being used by a pattern. Direct imports from Icon/Expensicons are deprecated. Please use lazy loading hooks instead. Use `useMemoizedLazyExpensifyIcons` from @hooks/useLazyAsset. See docs/LAZY_ICONS_AND_ILLUSTRATIONS.md for details

Check warning on line 7 in src/components/LHNOptionsList/OptionRowLHN.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'@components/Icon/Expensicons' import is restricted from being used. Direct imports from @components/Icon/Expensicons are deprecated. Please use lazy loading hooks instead. Use `useMemoizedLazyExpensifyIcons` from @hooks/useLazyAsset. See docs/LAZY_ICONS_AND_ILLUSTRATIONS.md for details
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {useSession} from '@components/OnyxListItemProvider';
import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
Expand All @@ -22,6 +22,7 @@
import DateUtils from '@libs/DateUtils';
import DomUtils from '@libs/DomUtils';
import {containsCustomEmoji as containsCustomEmojiUtils, containsOnlyCustomEmoji} from '@libs/EmojiUtils';
import FS from '@libs/Fullstory';
import {shouldOptionShowTooltip, shouldUseBoldText} from '@libs/OptionsListUtils';
import Performance from '@libs/Performance';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
Expand Down Expand Up @@ -167,6 +168,8 @@
const subscriptAvatarBorderColor = isOptionFocused ? focusedBackgroundColor : theme.sidebar;
const firstIcon = optionItem.icons?.at(0);

const alternateTextFSClass = FS.getChatFSClass(report);

const onOptionPress = (event: GestureResponderEvent | KeyboardEvent | undefined) => {
Performance.markStart(CONST.TIMING.OPEN_REPORT);
Timing.start(CONST.TIMING.OPEN_REPORT);
Expand Down Expand Up @@ -299,7 +302,7 @@
style={alternateTextStyle}
numberOfLines={1}
accessibilityLabel={translate('accessibilityHints.lastChatMessagePreview')}
fsClass={CONST.FULLSTORY.CLASS.MASK}
fsClass={alternateTextFSClass}
>
{alternateTextContainsCustomEmojiWithText ? (
<TextWithEmojiFragment
Expand All @@ -316,7 +319,7 @@
{optionItem?.descriptiveText ? (
<View
style={[styles.flexWrap]}
fsClass={CONST.FULLSTORY.CLASS.MASK}
fsClass={alternateTextFSClass}
>
<Text style={[styles.textLabel]}>{optionItem.descriptiveText}</Text>
</View>
Expand Down
9 changes: 7 additions & 2 deletions src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import convertToLTR from '@libs/convertToLTR';
import {canUseTouchScreen, hasHoverSupport} from '@libs/DeviceCapabilities';
import {containsCustomEmoji, containsOnlyCustomEmoji} from '@libs/EmojiUtils';
import type {ForwardedFSClassProps} from '@libs/Fullstory/types';
import getButtonState from '@libs/getButtonState';
import mergeRefs from '@libs/mergeRefs';
import Parser from '@libs/Parser';
Expand All @@ -33,7 +34,7 @@
import FormHelpMessage from './FormHelpMessage';
import Hoverable from './Hoverable';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';

Check warning on line 37 in src/components/MenuItem.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'./Icon/Expensicons' import is restricted from being used by a pattern. Direct imports from Icon/Expensicons are deprecated. Please use lazy loading hooks instead. Use `useMemoizedLazyExpensifyIcons` from @hooks/useLazyAsset. See docs/LAZY_ICONS_AND_ILLUSTRATIONS.md for details
import {MenuItemGroupContext} from './MenuItemGroup';
import PlaidCardFeedIcon from './PlaidCardFeedIcon';
import type {PressableRef} from './Pressable/GenericPressable/types';
Expand Down Expand Up @@ -64,7 +65,7 @@
icon?: undefined;
};

type MenuItemBaseProps = {
type MenuItemBaseProps = ForwardedFSClassProps & {
/** Reference to the outer element */
ref?: PressableRef | Ref<View>;

Expand Down Expand Up @@ -518,6 +519,7 @@
copyValue = title,
copyable = false,
hasSubMenuItems = false,
forwardedFSClass,
ref,
isFocused,
}: MenuItemProps) {
Expand Down Expand Up @@ -848,7 +850,10 @@
</Text>
)}
{(!!title || !!shouldShowTitleIcon) && (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mw100, titleWrapperStyle]}>
<View
style={[styles.flexRow, styles.alignItemsCenter, styles.mw100, titleWrapperStyle]}
fsClass={forwardedFSClass}
>
{!!title && (shouldRenderAsHTML || (shouldParseTitle && !!html.length)) && (
<View style={styles.renderHTMLTitle}>
<RenderHTML html={processedTitle} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import ControlSelection from '@libs/ControlSelection';
import canUseTouchScreen from '@libs/DeviceCapabilities/canUseTouchScreen';
import type {ForwardedFSClassProps} from '@libs/Fullstory/types';
import {getTransactionPendingAction, isTransactionPendingDelete} from '@libs/TransactionUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import type {Report, TransactionViolation} from '@src/types/onyx';
import type {TransactionWithOptionalHighlight} from './MoneyRequestReportTransactionList';

type MoneyRequestReportTransactionItemProps = ForwardedFSClassProps & {
type MoneyRequestReportTransactionItemProps = {
/** The transaction that is being displayed */
transaction: TransactionWithOptionalHighlight;

Expand Down Expand Up @@ -80,7 +79,6 @@ function MoneyRequestReportTransactionItem({
amountColumnSize,
taxAmountColumnSize,
scrollToNewTransaction,
forwardedFSClass,
onArrowRightPress,
}: MoneyRequestReportTransactionItemProps) {
const {translate} = useLocalize();
Expand Down Expand Up @@ -137,7 +135,6 @@ function MoneyRequestReportTransactionItem({
disabled={isTransactionPendingDelete(transaction)}
ref={viewRef}
wrapperStyle={[animatedHighlightStyle, styles.userSelectNone]}
forwardedFSClass={forwardedFSClass}
>
<TransactionItemRow
transactionItem={transaction}
Expand Down
Loading
Loading