Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate NVPs to their new keys #37556

Merged
merged 24 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
28 changes: 18 additions & 10 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ONYXKEYS = {
ACCOUNT_MANAGER_REPORT_ID: 'accountManagerReportID',

/** Boolean flag only true when first set */
NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER: 'isFirstTimeNewExpensifyUser',
NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER: 'nvp_isFirstTimeNewExpensifyUser',

/** Holds an array of client IDs which is used for multi-tabs on web in order to know
* which tab is the leader, and which ones are the followers */
Expand Down Expand Up @@ -109,22 +109,28 @@ const ONYXKEYS = {
NVP_PRIORITY_MODE: 'nvp_priorityMode',

/** Contains the users's block expiration (if they have one) */
NVP_BLOCKED_FROM_CONCIERGE: 'private_blockedFromConcierge',
NVP_BLOCKED_FROM_CONCIERGE: 'nvp_private_blockedFromConcierge',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would really be great to group all these together under an NVP key like:

ONYXKEYS: {
    NVP: {
        BLOCKED_FROM_CONCIERGE: 'nvp_private_blockedFromConcierge',
    },
};

Or if not that, at least put all the NVPs next to each other in this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving them to be together mostly because I don't know how to make my IDE refactor this automatically and I don't want to have to update 420 files.


/** A unique identifier that each user has that's used to send notifications */
NVP_PRIVATE_PUSH_NOTIFICATION_ID: 'private_pushNotificationID',
NVP_PRIVATE_PUSH_NOTIFICATION_ID: 'nvp_private_pushNotificationID',

/** The NVP with the last payment method used per policy */
NVP_LAST_PAYMENT_METHOD: 'nvp_lastPaymentMethod',
NVP_LAST_PAYMENT_METHOD: 'nvp_private_lastPaymentMethod',

/** This NVP holds to most recent waypoints that a person has used when creating a distance request */
NVP_RECENT_WAYPOINTS: 'expensify_recentWaypoints',

/** This NVP will be `true` if the user has ever dismissed the engagement modal on either OldDot or NewDot. If it becomes true it should stay true forever. */
NVP_HAS_DISMISSED_IDLE_PANEL: 'hasDismissedIdlePanel',
NVP_HAS_DISMISSED_IDLE_PANEL: 'nvp_hasDismissedIdlePanel',

/** This NVP contains the choice that the user made on the engagement modal */
NVP_INTRO_SELECTED: 'introSelected',
NVP_INTRO_SELECTED: 'nvp_introSelected',

/** This NVP contains the active policyID */
NVP_ACTIVE_POLICY_ID: 'nvp_expensify_activePolicyID',

/** This NVP contains the referral banners the user dismissed */
NVP_DISMISSED_REFERRAL_BANNERS: 'dismissedReferralBanners',

/** Does this user have push notifications enabled for this device? */
PUSH_NOTIFICATIONS_ENABLED: 'pushNotificationsEnabled',
Expand All @@ -146,7 +152,7 @@ const ONYXKEYS = {
ONFIDO_APPLICANT_ID: 'onfidoApplicantID',

/** Indicates which locale should be used */
NVP_PREFERRED_LOCALE: 'preferredLocale',
NVP_PREFERRED_LOCALE: 'nvp_preferredLocale',

/** User's Expensify Wallet */
USER_WALLET: 'userWallet',
Expand All @@ -170,7 +176,7 @@ const ONYXKEYS = {
CARD_LIST: 'cardList',

/** Whether the user has tried focus mode yet */
NVP_TRY_FOCUS_MODE: 'tryFocusMode',
NVP_TRY_FOCUS_MODE: 'nvp_tryFocusMode',

/** Whether the user has been shown the hold educational interstitial yet */
NVP_HOLD_USE_EXPLAINED: 'holdUseExplained',
Expand All @@ -188,10 +194,10 @@ const ONYXKEYS = {
REIMBURSEMENT_ACCOUNT: 'reimbursementAccount',

/** Store preferred skintone for emoji */
PREFERRED_EMOJI_SKIN_TONE: 'preferredEmojiSkinTone',
PREFERRED_EMOJI_SKIN_TONE: 'nvp_expensify_preferredEmojiSkinTone',

/** Store frequently used emojis for this user */
FREQUENTLY_USED_EMOJIS: 'frequentlyUsedEmojis',
FREQUENTLY_USED_EMOJIS: 'expensify_frequentlyUsedEmojis',

/** Stores Workspace ID that will be tied to reimbursement account during setup */
REIMBURSEMENT_ACCOUNT_WORKSPACE_ID: 'reimbursementAccountWorkspaceID',
Expand Down Expand Up @@ -568,6 +574,8 @@ type OnyxValuesMapping = {
[ONYXKEYS.LOGS]: Record<number, OnyxTypes.Log>;
[ONYXKEYS.SHOULD_STORE_LOGS]: boolean;
[ONYXKEYS.CACHED_PDF_PATHS]: Record<string, string>;
[ONYXKEYS.NVP_ACTIVE_POLICY_ID]: string;
[ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS]: OnyxTypes.DismissedReferralBanners;
};

type OnyxValues = OnyxValuesMapping & OnyxCollectionValuesMapping & OnyxFormValuesMapping & OnyxFormDraftValuesMapping;
Expand Down
5 changes: 2 additions & 3 deletions src/components/ReferralProgramCTA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Navigation from '@src/libs/Navigation/Navigation';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {DismissedReferralBanners} from '@src/types/onyx/Account';
import type DismissedReferralBanners from '@src/types/onyx/DismissedReferralBanners';
import Icon from './Icon';
import {Close} from './Icon/Expensicons';
import {PressableWithoutFeedback} from './Pressable';
Expand Down Expand Up @@ -81,8 +81,7 @@
}

export default withOnyx<ReferralProgramCTAProps, ReferralProgramCTAOnyxProps>({
dismissedReferralBanners: {

Check failure on line 84 in src/components/ReferralProgramCTA.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Type '{ key: "dismissedReferralBanners"; }' is not assignable to type 'OnyxPropMapping<ReferralProgramCTAProps, ReferralProgramCTAOnyxProps, "dismissedReferralBanners"> | OnyxPropCollectionMapping<...>'.
key: ONYXKEYS.ACCOUNT,
selector: (data) => data?.dismissedReferralBanners ?? {},
key: ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS,
},
})(ReferralProgramCTA);
6 changes: 2 additions & 4 deletions src/libs/actions/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -961,11 +961,9 @@ function dismissReferralBanner(type: ValueOf<typeof CONST.REFERRAL_PROGRAM.CONTE
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.ACCOUNT,
key: ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS,
value: {
dismissedReferralBanners: {
[type]: true,
},
[type]: true,
},
},
];
Expand Down
3 changes: 2 additions & 1 deletion src/libs/migrateOnyx.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Log from './Log';
import KeyReportActionsDraftByReportActionID from './migrations/KeyReportActionsDraftByReportActionID';
import NVPMigration from './migrations/NVPMigration';
import RemoveEmptyReportActionsDrafts from './migrations/RemoveEmptyReportActionsDrafts';
import RenameReceiptFilename from './migrations/RenameReceiptFilename';
import TransactionBackupsToCollection from './migrations/TransactionBackupsToCollection';
Expand All @@ -10,7 +11,7 @@ export default function (): Promise<void> {

return new Promise((resolve) => {
// Add all migrations to an array so they are executed in order
const migrationPromises = [RenameReceiptFilename, KeyReportActionsDraftByReportActionID, TransactionBackupsToCollection, RemoveEmptyReportActionsDrafts];
const migrationPromises = [RenameReceiptFilename, KeyReportActionsDraftByReportActionID, TransactionBackupsToCollection, RemoveEmptyReportActionsDrafts, NVPMigration];

// Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the
// previous promise to finish before moving onto the next one.
Expand Down
64 changes: 64 additions & 0 deletions src/libs/migrations/NVPMigration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import after from 'lodash/after';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';

const migrations = {

This comment was marked as resolved.

// eslint-disable-next-line @typescript-eslint/naming-convention
nvp_lastPaymentMethod: ONYXKEYS.NVP_LAST_PAYMENT_METHOD,
isFirstTimeNewExpensifyUser: ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER,
preferredLocale: ONYXKEYS.NVP_PREFERRED_LOCALE,
preferredEmojiSkinTone: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE,
frequentlyUsedEmojis: ONYXKEYS.FREQUENTLY_USED_EMOJIS,
// eslint-disable-next-line @typescript-eslint/naming-convention
private_blockedFromConcierge: ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE,
// eslint-disable-next-line @typescript-eslint/naming-convention
private_pushNotificationID: ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID,
tryFocusMode: ONYXKEYS.NVP_TRY_FOCUS_MODE,
introSelected: ONYXKEYS.NVP_INTRO_SELECTED,
hasDismissedIdlePanel: ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL,
};

// This migration changes the keys of all the NVP related keys so that they are standardized
export default function () {
return new Promise<void>((resolve) => {
// It's 1 more because activePolicyID is not in the migrations object above as it is nested inside an object
const resolveWhenDone = after(Object.entries(migrations).length + 1, () => resolve());

for (const [oldKey, newKey] of Object.entries(migrations)) {
const connectionID = Onyx.connect({
// @ts-expect-error oldKey is a variable
key: oldKey,
callback: (value) => {
Onyx.disconnect(connectionID);
if (value !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB: I'm kind of surprised that there aren't lint warnings to switch these to early returns. I guess it's because there is no return statement, but I think it would be nice to follow the style of early returns so the code style is consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this approach more because if I do early return I will need to call resolveWhenDone twice

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard, changing this given I need to pass resolveWhenDone to the promise too

// @ts-expect-error These keys are variables, so we can't check the type
Onyx.multiSet({
[newKey]: value,
[oldKey]: null,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been a while since I've done the migrations, but do you know if it's a bad thing that this doesn't wait for the multiSet() promise to be resolved before calling resolveWhenDone()? I think it could technically mean that the migration finishes before the actual changes are committed to storage. If the app then tries to load in that state, it could cause issues (even fatal errors maybe).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I just noticed this in while writing the message above, fixing it.

}
resolveWhenDone();
},
});
}
const connectionID = Onyx.connect({
key: ONYXKEYS.ACCOUNT,
callback: (value) => {
Onyx.disconnect(connectionID);
// @ts-expect-error we are removing this property, so it is not in the type anymore
if (value?.activePolicyID) {
// @ts-expect-error we are removing this property, so it is not in the type anymore
const activePolicyID = value.activePolicyID;
const newValue = {...value};
// @ts-expect-error we are removing this property, so it is not in the type anymore
delete newValue.activePolicyID;
Onyx.multiSet({
[ONYXKEYS.NVP_ACTIVE_POLICY_ID]: activePolicyID,
[ONYXKEYS.ACCOUNT]: newValue,
});
}
resolveWhenDone();
},
});
});
}
5 changes: 2 additions & 3 deletions src/pages/NewChatPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type * as OnyxTypes from '@src/types/onyx';
import type {DismissedReferralBanners} from '@src/types/onyx/Account';
import type DismissedReferralBanners from '@src/types/onyx/DismissedReferralBanners';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import type DismissedReferralBanners from '@src/types/onyx/DismissedReferralBanners';

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, please apply these changes in this file:

-   dismissedReferralBanners: DismissedReferralBanners;
+   dismissedReferralBanners: OnyxEntry<OnyxTypes.DismissedReferralBanners>;

-                           shouldShowReferralCTA={!dismissedReferralBanners[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT]}
+                           shouldShowReferralCTA={!dismissedReferralBanners?.[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT]}


type NewChatPageWithOnyxProps = {
/** All reports shared with the user */
Expand Down Expand Up @@ -286,9 +286,8 @@
NewChatPage.displayName = 'NewChatPage';

export default withOnyx<NewChatPageProps, NewChatPageWithOnyxProps>({
dismissedReferralBanners: {

Check failure on line 289 in src/pages/NewChatPage.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Type '{ key: "dismissedReferralBanners"; }' is not assignable to type 'OnyxPropMapping<NewChatPageProps, NewChatPageWithOnyxProps, "dismissedReferralBanners"> | OnyxPropCollectionMapping<NewChatPageProps, NewChatPageWithOnyxProps, "dismissedReferralBanners">'.
key: ONYXKEYS.ACCOUNT,
selector: (data) => data?.dismissedReferralBanners ?? {},
key: ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS,
},
reports: {
key: ONYXKEYS.COLLECTION.REPORT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,7 @@ MoneyTemporaryForRefactorRequestParticipantsSelector.displayName = 'MoneyTempora

export default withOnyx({
dismissedReferralBanners: {
key: ONYXKEYS.ACCOUNT,
selector: (data) => data.dismissedReferralBanners || {},
key: ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS,
},
reports: {
key: ONYXKEYS.COLLECTION.REPORT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,7 @@ MoneyRequestParticipantsSelector.defaultProps = defaultProps;

export default withOnyx({
dismissedReferralBanners: {
key: ONYXKEYS.ACCOUNT,
selector: (data) => data.dismissedReferralBanners || {},
key: ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS,
},
reports: {
key: ONYXKEYS.COLLECTION.REPORT,
Expand Down
7 changes: 3 additions & 4 deletions src/pages/workspace/WorkspaceNewRoomPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {NewRoomForm} from '@src/types/form/NewRoomForm';
import INPUT_IDS from '@src/types/form/NewRoomForm';
import type {Account, Policy, Report as ReportType, Session} from '@src/types/onyx';
import type {Policy, Report as ReportType, Session} from '@src/types/onyx';
import type * as OnyxCommon from '@src/types/onyx/OnyxCommon';
import {isEmptyObject} from '@src/types/utils/EmptyObject';

Expand All @@ -53,7 +53,7 @@ type WorkspaceNewRoomPageOnyxProps = {
session: OnyxEntry<Session>;

/** policyID for main workspace */
activePolicyID: OnyxEntry<Required<Account>['activePolicyID']>;
activePolicyID: OnyxEntry<Required<string>>;
};

type WorkspaceNewRoomPageProps = WorkspaceNewRoomPageOnyxProps;
Expand Down Expand Up @@ -342,8 +342,7 @@ export default withOnyx<WorkspaceNewRoomPageProps, WorkspaceNewRoomPageOnyxProps
key: ONYXKEYS.SESSION,
},
activePolicyID: {
key: ONYXKEYS.ACCOUNT,
selector: (account) => account?.activePolicyID ?? null,
key: ONYXKEYS.NVP_ACTIVE_POLICY_ID,
initialValue: null,
},
})(WorkspaceNewRoomPage);
14 changes: 1 addition & 13 deletions src/types/onyx/Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@ import type * as OnyxCommon from './OnyxCommon';

type TwoFactorAuthStep = ValueOf<typeof CONST.TWO_FACTOR_AUTH_STEPS> | '';

type DismissedReferralBanners = {
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST]?: boolean;
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT]?: boolean;
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY]?: boolean;
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND]?: boolean;
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE]?: boolean;
};

type Account = {
/** Whether SAML is enabled for the current account */
isSAMLEnabled?: boolean;
Expand Down Expand Up @@ -64,15 +56,11 @@ type Account = {
/** Whether a sign is loading */
isLoading?: boolean;

/** The active policy ID. Initiating a SmartScan will create an expense on this policy by default. */
activePolicyID?: string;

errors?: OnyxCommon.Errors | null;
success?: string;
codesAreCopied?: boolean;
twoFactorAuthStep?: TwoFactorAuthStep;
dismissedReferralBanners?: DismissedReferralBanners;
};

export default Account;
export type {TwoFactorAuthStep, DismissedReferralBanners};
export type {TwoFactorAuthStep};
11 changes: 11 additions & 0 deletions src/types/onyx/DismissedReferralBanners.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type CONST from '@src/CONST';

type DismissedReferralBanners = {
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST]?: boolean;
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT]?: boolean;
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY]?: boolean;
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND]?: boolean;
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE]?: boolean;
};

export default DismissedReferralBanners;
Comment on lines +1 to +11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update the description to also include the background for these changes for this dismissedReferralBanner nvp?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow, what background? 😕

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explanation for why the changes to this nvp, it sees like it was refactored more than others in this PR

2 changes: 2 additions & 0 deletions src/types/onyx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type Credentials from './Credentials';
import type Currency from './Currency';
import type {CurrencyList} from './Currency';
import type CustomStatusDraft from './CustomStatusDraft';
import type DismissedReferralBanners from './DismissedReferralBanners';
import type Download from './Download';
import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji';
import type {FundList} from './Fund';
Expand Down Expand Up @@ -85,6 +86,7 @@ export type {
Currency,
CurrencyList,
CustomStatusDraft,
DismissedReferralBanners,
Download,
FrequentlyUsedEmoji,
Fund,
Expand Down
Loading