Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 1 addition & 3 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import type CONST from './CONST';
import type * as FormTypes from './types/form';
Expand Down Expand Up @@ -657,12 +656,11 @@ type OnyxFormDraftKey = keyof OnyxFormDraftValuesMapping;
type OnyxValueKey = keyof OnyxValuesMapping;

type OnyxKey = OnyxValueKey | OnyxCollectionKey | OnyxFormKey | OnyxFormDraftKey;
type OnyxValue<TOnyxKey extends OnyxKey> = TOnyxKey extends keyof OnyxCollectionValuesMapping ? OnyxCollection<OnyxValues[TOnyxKey]> : OnyxEntry<OnyxValues[TOnyxKey]>;

type MissingOnyxKeysError = `Error: Types don't match, OnyxKey type is missing: ${Exclude<AllOnyxKeys, OnyxKey>}`;
/** If this type errors, it means that the `OnyxKey` type is missing some keys. */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type AssertOnyxKeys = AssertTypesEqual<AllOnyxKeys, OnyxKey, MissingOnyxKeysError>;

export default ONYXKEYS;
export type {OnyxValues, OnyxKey, OnyxCollectionKey, OnyxValue, OnyxValueKey, OnyxFormKey, OnyxFormValuesMapping, OnyxFormDraftKey, OnyxCollectionValuesMapping};
export type {OnyxCollectionKey, OnyxCollectionValuesMapping, OnyxFormDraftKey, OnyxFormKey, OnyxFormValuesMapping, OnyxKey, OnyxValueKey, OnyxValues};
3 changes: 2 additions & 1 deletion src/components/createOnyxContext.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import Str from 'expensify-common/lib/str';
import type {ComponentType, ForwardedRef, ForwardRefExoticComponent, PropsWithoutRef, ReactNode, RefAttributes} from 'react';
import React, {createContext, forwardRef, useContext} from 'react';
import type {OnyxValue} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import getComponentDisplayName from '@libs/getComponentDisplayName';
import type {OnyxKey, OnyxValue} from '@src/ONYXKEYS';
import type {OnyxKey} from '@src/ONYXKEYS';
import type ChildrenProps from '@src/types/utils/ChildrenProps';

// Provider types
Expand Down
6 changes: 3 additions & 3 deletions src/libs/actions/FormActions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {NullishDeep, OnyxValue} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import type {NullishDeep} from 'react-native-onyx';
import type {OnyxFormDraftKey, OnyxFormKey, OnyxValue} from '@src/ONYXKEYS';
import type {OnyxFormDraftKey, OnyxFormKey} from '@src/ONYXKEYS';
import type * as OnyxCommon from '@src/types/onyx/OnyxCommon';

function setIsLoading(formID: OnyxFormKey, isLoading: boolean) {
Expand Down Expand Up @@ -31,4 +31,4 @@ function clearDraftValues(formID: OnyxFormKey) {
Onyx.set(`${formID}Draft`, null);
}

export {setDraftValues, setErrorFields, setErrors, clearErrors, clearErrorFields, setIsLoading, clearDraftValues};
export {clearDraftValues, clearErrorFields, clearErrors, setDraftValues, setErrorFields, setErrors, setIsLoading};
49 changes: 10 additions & 39 deletions src/pages/NewChatPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import KeyboardAvoidingView from '@components/KeyboardAvoidingView';
import OfflineIndicator from '@components/OfflineIndicator';
import {useOptionsList} from '@components/OptionListContextProvider';
Expand All @@ -25,32 +24,21 @@ import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import type {SelectedParticipant} from '@src/types/onyx/NewGroupChatDraft';

type NewChatPageWithOnyxProps = {
/** New group chat draft data */
newGroupDraft: OnyxEntry<OnyxTypes.NewGroupChatDraft>;

/** All of the personal details for everyone */
personalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>;

betas: OnyxEntry<OnyxTypes.Beta[]>;

/** An object that holds data about which referral banners have been dismissed */
dismissedReferralBanners: OnyxEntry<OnyxTypes.DismissedReferralBanners>;

/** Whether we are searching for reports in the server */
isSearchingForReports: OnyxEntry<boolean>;
};

type NewChatPageProps = NewChatPageWithOnyxProps & {
type NewChatPageProps = {
isGroupChat?: boolean;
};

const excludedGroupEmails = CONST.EXPENSIFY_EMAILS.filter((value) => value !== CONST.EMAIL.CONCIERGE);

function NewChatPage({betas, isGroupChat, personalDetails, isSearchingForReports, dismissedReferralBanners, newGroupDraft}: NewChatPageProps) {
function NewChatPage({isGroupChat}: NewChatPageProps) {
const [dismissedReferralBanners] = useOnyx(ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS);
const [newGroupDraft] = useOnyx(ONYXKEYS.NEW_GROUP_CHAT_DRAFT);
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [betas] = useOnyx(ONYXKEYS.BETAS);
const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false});

const {translate} = useLocalize();

const styles = useThemeStyles();
Expand Down Expand Up @@ -311,21 +299,4 @@ function NewChatPage({betas, isGroupChat, personalDetails, isSearchingForReports

NewChatPage.displayName = 'NewChatPage';

export default withOnyx<NewChatPageProps, NewChatPageWithOnyxProps>({
dismissedReferralBanners: {
key: ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS,
},
newGroupDraft: {
key: ONYXKEYS.NEW_GROUP_CHAT_DRAFT,
},
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
betas: {
key: ONYXKEYS.BETAS,
},
isSearchingForReports: {
key: ONYXKEYS.IS_SEARCHING_FOR_REPORTS,
initWithStoredValues: false,
},
})(NewChatPage);
export default NewChatPage;
107 changes: 39 additions & 68 deletions src/pages/ProfilePage.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type {StackScreenProps} from '@react-navigation/stack';
import Str from 'expensify-common/lib/str';
import React, {useEffect} from 'react';
import React, {useEffect, useMemo} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import AutoUpdateTime from '@components/AutoUpdateTime';
import Avatar from '@components/Avatar';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
Expand Down Expand Up @@ -36,31 +36,11 @@ import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {PersonalDetails, PersonalDetailsList, PersonalDetailsMetadata, Report, Session} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {PersonalDetails, Report} from '@src/types/onyx';
import type {EmptyObject} from '@src/types/utils/EmptyObject';
import {isEmptyObject} from '@src/types/utils/EmptyObject';

type ProfilePageOnyxProps = {
/** The personal details of the person who is logged in */
personalDetails: OnyxEntry<PersonalDetailsList>;

/** Loading status of the personal details */
personalDetailsMetadata: OnyxEntry<Record<string, PersonalDetailsMetadata>>;

/** The report currently being looked at */
report: OnyxEntry<Report>;

/** The list of all reports
* ONYXKEYS.COLLECTION.REPORT is needed for report key function
*/
// eslint-disable-next-line react/no-unused-prop-types
reports: OnyxCollection<Report>;

/** Session info for the currently logged in user. */
session: OnyxEntry<Session>;
};

type ProfilePageProps = ProfilePageOnyxProps & StackScreenProps<ProfileNavigatorParamList, typeof SCREENS.PROFILE_ROOT>;
type ProfilePageProps = StackScreenProps<ProfileNavigatorParamList, typeof SCREENS.PROFILE_ROOT>;

/**
* Gets the phone number to display for SMS logins
Expand All @@ -77,7 +57,38 @@ const getPhoneNumber = ({login = '', displayName = ''}: PersonalDetails | EmptyO
return login ? Str.removeSMSDomain(login) : '';
};

function ProfilePage({personalDetails, personalDetailsMetadata, route, session, report}: ProfilePageProps) {
/**
* This function narrow down the data from Onyx to just the properties that we want to trigger a re-render of the component. This helps minimize re-rendering
* and makes the entire component more performant because it's not re-rendering when a bunch of properties change which aren't ever used in the UI.
*/
const chatReportSelector = (report: OnyxEntry<Report>): OnyxEntry<Report> =>
report && {
reportID: report.reportID,
participantAccountIDs: report.participantAccountIDs,
parentReportID: report.parentReportID,
parentReportActionID: report.parentReportActionID,
type: report.type,
chatType: report.chatType,
isPolicyExpenseChat: report.isPolicyExpenseChat,
};

function ProfilePage({route}: ProfilePageProps) {
const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {selector: chatReportSelector});
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [personalDetailsMetadata] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_METADATA);
const [session] = useOnyx(ONYXKEYS.SESSION);

const reportKey = useMemo(() => {
const accountID = Number(route.params?.accountID ?? 0);
const reportID = ReportUtils.getChatByParticipants([accountID], reports)?.reportID ?? '';

if ((Boolean(session) && Number(session?.accountID) === accountID) || SessionActions.isAnonymousUser() || !reportID) {
return `${ONYXKEYS.COLLECTION.REPORT}0` as const;
}
return `${ONYXKEYS.COLLECTION.REPORT}${reportID}` as const;
}, [reports, route.params?.accountID, session]);
const [report] = useOnyx(reportKey);

const styles = useThemeStyles();
const {translate, formatPhoneNumber} = useLocalize();
const accountID = Number(route.params?.accountID ?? 0);
Expand Down Expand Up @@ -247,44 +258,4 @@ function ProfilePage({personalDetails, personalDetailsMetadata, route, session,

ProfilePage.displayName = 'ProfilePage';

/**
* This function narrow down the data from Onyx to just the properties that we want to trigger a re-render of the component. This helps minimize re-rendering
* and makes the entire component more performant because it's not re-rendering when a bunch of properties change which aren't ever used in the UI.
*/
const chatReportSelector = (report: OnyxEntry<Report>): Report =>
(report && {
reportID: report.reportID,
participantAccountIDs: report.participantAccountIDs,
parentReportID: report.parentReportID,
parentReportActionID: report.parentReportActionID,
type: report.type,
chatType: report.chatType,
isPolicyExpenseChat: report.isPolicyExpenseChat,
}) as Report;

export default withOnyx<ProfilePageProps, ProfilePageOnyxProps>({
reports: {
key: ONYXKEYS.COLLECTION.REPORT,
selector: chatReportSelector,
},
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
personalDetailsMetadata: {
key: ONYXKEYS.PERSONAL_DETAILS_METADATA,
},
session: {
key: ONYXKEYS.SESSION,
},
report: {
key: ({route, session, reports}) => {
const accountID = Number(route.params?.accountID ?? 0);
const reportID = ReportUtils.getChatByParticipants([accountID], reports)?.reportID ?? '';

if ((Boolean(session) && Number(session?.accountID) === accountID) || SessionActions.isAnonymousUser() || !reportID) {
return `${ONYXKEYS.COLLECTION.REPORT}0`;
}
return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
},
},
})(ProfilePage);
export default ProfilePage;
33 changes: 6 additions & 27 deletions src/pages/settings/Preferences/PreferencesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Illustrations from '@components/Icon/Illustrations';
import LottieAnimations from '@components/LottieAnimations';
Expand All @@ -20,22 +19,12 @@ import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {PreferredTheme, PriorityMode, User as UserType} from '@src/types/onyx';

type PreferencesPageOnyxProps = {
/** The chat priority mode */
priorityMode: PriorityMode;
function PreferencesPage() {
const [priorityMode] = useOnyx(ONYXKEYS.NVP_PRIORITY_MODE);
const [user] = useOnyx(ONYXKEYS.USER);
const [preferredTheme] = useOnyx(ONYXKEYS.PREFERRED_THEME);

/** The app's color theme */
preferredTheme: PreferredTheme;

/** The details about the user that is signed in */
user: OnyxEntry<UserType>;
};

type PreferencesPageProps = PreferencesPageOnyxProps;

function PreferencesPage({priorityMode, preferredTheme, user}: PreferencesPageProps) {
const styles = useThemeStyles();
const {translate, preferredLocale} = useLocalize();
const {isSmallScreenWidth} = useWindowDimensions();
Expand Down Expand Up @@ -125,14 +114,4 @@ function PreferencesPage({priorityMode, preferredTheme, user}: PreferencesPagePr

PreferencesPage.displayName = 'PreferencesPage';

export default withOnyx<PreferencesPageProps, PreferencesPageOnyxProps>({
priorityMode: {
key: ONYXKEYS.NVP_PRIORITY_MODE,
},
user: {
key: ONYXKEYS.USER,
},
preferredTheme: {
key: ONYXKEYS.PREFERRED_THEME,
},
})(PreferencesPage);
export default PreferencesPage;
Loading