Skip to content

Commit

Permalink
Merge pull request #34842 from Expensify/tgolen-perma-dismiss-banners
Browse files Browse the repository at this point in the history
Allow users to permanently dismiss the referral banners
  • Loading branch information
tylerkaraszewski authored Feb 2, 2024
2 parents ba9cf0f + c5feb7e commit bdc554f
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 18 deletions.
11 changes: 8 additions & 3 deletions src/components/OptionsSelector/BaseOptionsSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const propTypes = {
/** Whether referral CTA should be displayed */
shouldShowReferralCTA: PropTypes.bool,

/** A method triggered when the user closes the call to action banner */
onCallToActionClosed: PropTypes.func,

/** Referral content type */
referralContentType: PropTypes.string,

Expand All @@ -53,6 +56,7 @@ const propTypes = {
const defaultProps = {
shouldDelayFocus: false,
shouldShowReferralCTA: false,
onCallToActionClosed: () => {},
referralContentType: CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND,
safeAreaPaddingBottomStyle: {},
contentContainerStyles: [],
Expand All @@ -68,7 +72,7 @@ class BaseOptionsSelector extends Component {
this.updateFocusedIndex = this.updateFocusedIndex.bind(this);
this.scrollToIndex = this.scrollToIndex.bind(this);
this.selectRow = this.selectRow.bind(this);
this.handleReferralModal = this.handleReferralModal.bind(this);
this.closeReferralModal = this.closeReferralModal.bind(this);
this.selectFocusedOption = this.selectFocusedOption.bind(this);
this.addToSelection = this.addToSelection.bind(this);
this.updateSearchValue = this.updateSearchValue.bind(this);
Expand Down Expand Up @@ -262,8 +266,9 @@ class BaseOptionsSelector extends Component {
this.props.onChangeText(value);
}

handleReferralModal() {
closeReferralModal() {
this.setState((prevState) => ({shouldShowReferralModal: !prevState.shouldShowReferralModal}));
this.props.onCallToActionClosed(this.props.referralContentType);
}

handleFocusIn() {
Expand Down Expand Up @@ -652,7 +657,7 @@ class BaseOptionsSelector extends Component {
<View style={[this.props.themeStyles.ph5, this.props.themeStyles.pb5, this.props.themeStyles.flexShrink0]}>
<ReferralProgramCTA
referralContentType={this.props.referralContentType}
onCloseButtonPress={this.handleReferralModal}
onCloseButtonPress={this.closeReferralModal}
/>
</View>
)}
Expand Down
10 changes: 10 additions & 0 deletions src/libs/API/parameters/DismissReferralBannerParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type {ValueOf} from 'type-fest';
import type CONST from '@src/CONST';

type ContentTypes = ValueOf<typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES>;

type DismissReferralBannerParams = {
type: ContentTypes;
};

export default DismissReferralBannerParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type {default as ConnectBankAccountWithPlaidParams} from './ConnectBankAc
export type {default as DeleteContactMethodParams} from './DeleteContactMethodParams';
export type {default as DeletePaymentBankAccountParams} from './DeletePaymentBankAccountParams';
export type {default as DeletePaymentCardParams} from './DeletePaymentCardParams';
export type {default as DismissReferralBannerParams} from './DismissReferralBannerParams';
export type {default as ExpandURLPreviewParams} from './ExpandURLPreviewParams';
export type {default as GetMissingOnyxMessagesParams} from './GetMissingOnyxMessagesParams';
export type {default as GetNewerActionsParams} from './GetNewerActionsParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type UpdateBeneficialOwnersForBankAccountParams from './parameters/Update
type ApiRequest = ValueOf<typeof CONST.API_REQUEST_TYPE>;

const WRITE_COMMANDS = {
DISMISS_REFERRAL_BANNER: 'DismissReferralBanner',
UPDATE_PREFERRED_LOCALE: 'UpdatePreferredLocale',
RECONNECT_APP: 'ReconnectApp',
OPEN_PROFILE: 'OpenProfile',
Expand Down Expand Up @@ -120,6 +121,7 @@ const WRITE_COMMANDS = {
type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;

type WriteCommandParameters = {
[WRITE_COMMANDS.DISMISS_REFERRAL_BANNER]: Parameters.DismissReferralBannerParams;
[WRITE_COMMANDS.UPDATE_PREFERRED_LOCALE]: Parameters.UpdatePreferredLocaleParams;
[WRITE_COMMANDS.RECONNECT_APP]: Parameters.ReconnectAppParams;
[WRITE_COMMANDS.OPEN_PROFILE]: Parameters.OpenProfileParams;
Expand Down
22 changes: 22 additions & 0 deletions src/libs/actions/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -843,9 +843,31 @@ function clearDraftCustomStatus() {
Onyx.merge(ONYXKEYS.CUSTOM_STATUS_DRAFT, {text: '', emojiCode: '', clearAfter: ''});
}

function dismissReferralBanner(type: ValueOf<typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES>) {
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.ACCOUNT,
value: {
dismissedReferralBanners: {
[type]: true,
},
},
},
];
API.write(
WRITE_COMMANDS.DISMISS_REFERRAL_BANNER,
{type},
{
optimisticData,
},
);
}

export {
clearFocusModeNotification,
closeAccount,
dismissReferralBanner,
resendValidateCode,
requestContactMethodValidateCode,
updateNewsletterSubscription,
Expand Down
18 changes: 16 additions & 2 deletions src/pages/NewChatPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as ReportUtils from '@libs/ReportUtils';
import variables from '@styles/variables';
import * as Report from '@userActions/Report';
import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import personalDetailsPropType from './personalDetailsPropType';
Expand All @@ -36,6 +37,9 @@ const propTypes = {
/** All reports shared with the user */
reports: PropTypes.objectOf(reportPropTypes),

/** An object that holds data about which referral banners have been dismissed */
dismissedReferralBanners: PropTypes.objectOf(PropTypes.bool),

...windowDimensionsPropTypes,

...withLocalizePropTypes,
Expand All @@ -46,14 +50,15 @@ const propTypes = {

const defaultProps = {
betas: [],
dismissedReferralBanners: {},
personalDetails: {},
reports: {},
isSearchingForReports: false,
};

const excludedGroupEmails = _.without(CONST.EXPENSIFY_EMAILS, CONST.EMAIL.CONCIERGE);

function NewChatPage({betas, isGroupChat, personalDetails, reports, translate, isSearchingForReports}) {
function NewChatPage({betas, isGroupChat, personalDetails, reports, translate, isSearchingForReports, dismissedReferralBanners}) {
const styles = useThemeStyles();
const [searchTerm, setSearchTerm] = useState('');
const [filteredRecentReports, setFilteredRecentReports] = useState([]);
Expand Down Expand Up @@ -230,6 +235,10 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate, i
updateOptions();
}, [didScreenTransitionEnd, updateOptions]);

const dismissCallToAction = (referralContentType) => {
User.dismissReferralBanner(referralContentType);
};

const {inputCallbackRef} = useAutoFocusInput();

return (
Expand Down Expand Up @@ -265,8 +274,9 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate, i
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
shouldShowOptions={isOptionsDataReady && didScreenTransitionEnd}
shouldShowConfirmButton
shouldShowReferralCTA
shouldShowReferralCTA={!dismissedReferralBanners[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT]}
referralContentType={CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT}
onCallToActionClosed={dismissCallToAction}
confirmButtonText={selectedOptions.length > 1 ? translate('newChatPage.createGroup') : translate('newChatPage.createChat')}
textInputAlert={isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''}
onConfirmSelection={createGroup}
Expand All @@ -291,6 +301,10 @@ export default compose(
withLocalize,
withWindowDimensions,
withOnyx({
dismissedReferralBanners: {
key: ONYXKEYS.ACCOUNT,
selector: (data) => data.dismissedReferralBanners || {},
},
reports: {
key: ONYXKEYS.COLLECTION.REPORT,
},
Expand Down
25 changes: 21 additions & 4 deletions src/pages/SearchPage/SearchPageFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
import React, {useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import ReferralProgramCTA from '@components/ReferralProgramCTA';
import useThemeStyles from '@hooks/useThemeStyles';
import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {DismissedReferralBanners} from '@src/types/onyx/Account';

function SearchPageFooter() {
const [shouldShowReferralCTA, setShouldShowReferralCTA] = useState(true);
type SearchPageFooterOnyxProps = {
dismissedReferralBanners: DismissedReferralBanners;
};
function SearchPageFooter({dismissedReferralBanners}: SearchPageFooterOnyxProps) {
const [shouldShowReferralCTA, setShouldShowReferralCTA] = useState(!dismissedReferralBanners[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND]);
const themeStyles = useThemeStyles();

const closeCallToActionBanner = () => {
setShouldShowReferralCTA(false);
User.dismissReferralBanner(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND);
};

return (
<>
{shouldShowReferralCTA && (
<View style={[themeStyles.pb5, themeStyles.flexShrink0]}>
<ReferralProgramCTA
referralContentType={CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND}
onCloseButtonPress={() => setShouldShowReferralCTA(false)}
onCloseButtonPress={closeCallToActionBanner}
/>
</View>
)}
Expand All @@ -24,4 +36,9 @@ function SearchPageFooter() {

SearchPageFooter.displayName = 'SearchPageFooter';

export default SearchPageFooter;
export default withOnyx<SearchPageFooterOnyxProps, SearchPageFooterOnyxProps>({
dismissedReferralBanners: {
key: ONYXKEYS.ACCOUNT,
selector: (data) => data?.dismissedReferralBanners ?? {},
},
})(SearchPageFooter);
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as ReportUtils from '@libs/ReportUtils';
import reportPropTypes from '@pages/reportPropTypes';
import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';

const propTypes = {
/** Beta features list */
betas: PropTypes.arrayOf(PropTypes.string),

/** An object that holds data about which referral banners have been dismissed */
dismissedReferralBanners: PropTypes.objectOf(PropTypes.bool),

/** Callback to request parent modal to go to next step, which should be split */
onFinish: PropTypes.func.isRequired,

Expand Down Expand Up @@ -64,6 +68,7 @@ const defaultProps = {
safeAreaPaddingBottomStyle: {},
reports: {},
betas: [],
dismissedReferralBanners: {},
didScreenTransitionEnd: false,
};

Expand All @@ -76,12 +81,14 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
safeAreaPaddingBottomStyle,
iouType,
iouRequestType,
dismissedReferralBanners,
didScreenTransitionEnd,
}) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [searchTerm, setSearchTerm] = useState('');
const [shouldShowReferralCTA, setShouldShowReferralCTA] = useState(true);
const referralContentType = iouType === CONST.IOU.TYPE.SEND ? CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY : CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST;
const [shouldShowReferralCTA, setShouldShowReferralCTA] = useState(!dismissedReferralBanners[referralContentType]);
const {isOffline} = useNetwork();
const personalDetails = usePersonalDetails();

Expand Down Expand Up @@ -251,7 +258,6 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
const hasPolicyExpenseChatParticipant = _.some(participants, (participant) => participant.isPolicyExpenseChat);
const shouldShowSplitBillErrorMessage = participants.length > 1 && hasPolicyExpenseChatParticipant;
const isAllowedToSplit = iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE;
const referralContentType = iouType === CONST.IOU.TYPE.SEND ? CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY : CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST;

const handleConfirmSelection = useCallback(() => {
if (shouldShowSplitBillErrorMessage) {
Expand All @@ -261,14 +267,19 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
onFinish();
}, [shouldShowSplitBillErrorMessage, onFinish]);

const closeCallToActionBanner = useCallback(() => {
setShouldShowReferralCTA(false);
User.dismissReferralBanner(referralContentType);
}, [referralContentType]);

const footerContent = useMemo(
() => (
<View>
{shouldShowReferralCTA && (
<View style={[styles.flexShrink0, !!participants.length && !shouldShowSplitBillErrorMessage && styles.pb5]}>
<ReferralProgramCTA
referralContentType={referralContentType}
onCloseButtonPress={() => setShouldShowReferralCTA(false)}
onCloseButtonPress={closeCallToActionBanner}
/>
</View>
)}
Expand All @@ -292,7 +303,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
)}
</View>
),
[handleConfirmSelection, participants.length, referralContentType, shouldShowSplitBillErrorMessage, shouldShowReferralCTA, styles, translate],
[handleConfirmSelection, participants.length, referralContentType, shouldShowSplitBillErrorMessage, shouldShowReferralCTA, styles, translate, closeCallToActionBanner],
);

const itemRightSideComponent = useCallback(
Expand Down Expand Up @@ -356,6 +367,10 @@ MoneyTemporaryForRefactorRequestParticipantsSelector.defaultProps = defaultProps
MoneyTemporaryForRefactorRequestParticipantsSelector.displayName = 'MoneyTemporaryForRefactorRequestParticipantsSelector';

export default withOnyx({
dismissedReferralBanners: {
key: ONYXKEYS.ACCOUNT,
selector: (data) => data.dismissedReferralBanners || {},
},
reports: {
key: ONYXKEYS.COLLECTION.REPORT,
},
Expand Down
Loading

0 comments on commit bdc554f

Please sign in to comment.