From 5fda1d15908add3b48791324564d788373243f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Wed, 17 Apr 2024 18:32:39 +0100 Subject: [PATCH 01/18] Fix typings across the project --- src/components/AvatarWithDisplayName.tsx | 6 +++--- src/languages/types.ts | 17 ++++++++------- src/libs/EmojiUtils.ts | 2 +- src/libs/ErrorUtils.ts | 21 ++++++++++--------- src/libs/PolicyUtils.ts | 2 +- src/libs/ReportActionsUtils.ts | 8 +++---- src/libs/ReportUtils.ts | 2 +- src/libs/actions/BankAccounts.ts | 3 +-- src/libs/actions/FormActions.ts | 2 +- src/libs/actions/IOU.ts | 12 +++++------ src/libs/actions/OnyxUpdates.ts | 6 +++--- src/libs/actions/Policy.ts | 2 +- src/libs/actions/Report.ts | 4 ++-- src/libs/migrations/RenameReceiptFilename.ts | 4 ++-- .../TransactionBackupsToCollection.ts | 4 ++-- src/pages/GroupChatNameEditPage.tsx | 3 ++- src/pages/NewChatPage.tsx | 4 +++- .../PrivateNotes/PrivateNotesEditPage.tsx | 6 +++--- .../PrivateNotes/PrivateNotesListPage.tsx | 6 +++--- .../components/BankAccountValidationForm.tsx | 3 ++- .../utils/getValuesForBeneficialOwner.ts | 3 ++- src/pages/ReportDetailsPage.tsx | 4 ++-- .../sidebar/ProfileAvatarWithIndicator.tsx | 3 +-- src/types/utils/isLoadingOnyxValue.ts | 4 ++-- tests/actions/IOUTest.ts | 4 ++-- 25 files changed, 70 insertions(+), 65 deletions(-) diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index c7a4ece0de97..51fa92e1fd48 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -1,6 +1,6 @@ import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -12,7 +12,7 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetails, Policy, Report, ReportActions} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, Policy, Report, ReportActions} from '@src/types/onyx'; import DisplayNames from './DisplayNames'; import MultipleAvatars from './MultipleAvatars'; import ParentNavigationSubtitle from './ParentNavigationSubtitle'; @@ -25,7 +25,7 @@ type AvatarWithDisplayNamePropsWithOnyx = { parentReportActions: OnyxEntry; /** Personal details of all users */ - personalDetails: OnyxCollection; + personalDetails: OnyxEntry; }; type AvatarWithDisplayNameProps = AvatarWithDisplayNamePropsWithOnyx & { diff --git a/src/languages/types.ts b/src/languages/types.ts index c365363f84af..35825ff01632 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -1,3 +1,4 @@ +import type {OnyxEntry} from 'react-native-onyx'; import type {ReportAction} from '@src/types/onyx'; import type en from './en'; @@ -43,15 +44,15 @@ type LocalTimeParams = { }; type EditActionParams = { - action: ReportAction | null; + action: OnyxEntry; }; type DeleteActionParams = { - action: ReportAction | null; + action: OnyxEntry; }; type DeleteConfirmationParams = { - action: ReportAction | null; + action: OnyxEntry; }; type BeginningOfChatHistoryDomainRoomPartOneParams = { @@ -298,11 +299,11 @@ type HeldRequestParams = {comment: string}; type DistanceRateOperationsParams = {count: number}; export type { - AdminCanceledRequestParams, - ApprovedAmountParams, AddressLineParams, + AdminCanceledRequestParams, AlreadySignedInParams, AmountEachParams, + ApprovedAmountParams, BeginningOfChatHistoryAdminRoomPartOneParams, BeginningOfChatHistoryAnnounceRoomPartOneParams, BeginningOfChatHistoryAnnounceRoomPartTwo, @@ -323,8 +324,10 @@ export type { FormattedMaxLengthParams, GoBackMessageParams, GoToRoomParams, + HeldRequestParams, InstantSummaryParams, LocalTimeParams, + LogSizeParams, LoggedInAsParams, ManagerApprovedAmountParams, ManagerApprovedParams, @@ -375,6 +378,7 @@ export type { UntilTimeParams, UpdatedTheDistanceParams, UpdatedTheRequestParams, + UsePlusButtonParams, UserIsAlreadyMemberParams, ViolationsAutoReportedRejectedExpenseParams, ViolationsCashExpenseWithNoReceiptParams, @@ -392,12 +396,9 @@ export type { ViolationsTaxOutOfPolicyParams, WaitingOnBankAccountParams, WalletProgramParams, - UsePlusButtonParams, WeSentYouMagicSignInLinkParams, WelcomeEnterMagicCodeParams, WelcomeNoteParams, WelcomeToRoomParams, ZipCodeExampleFormatParams, - LogSizeParams, - HeldRequestParams, }; diff --git a/src/libs/EmojiUtils.ts b/src/libs/EmojiUtils.ts index 3b189dbb084f..c8b384a5a97c 100644 --- a/src/libs/EmojiUtils.ts +++ b/src/libs/EmojiUtils.ts @@ -431,7 +431,7 @@ function suggestEmojis(text: string, lang: Locale, limit: number = CONST.AUTO_CO /** * Retrieve preferredSkinTone as Number to prevent legacy 'default' String value */ -const getPreferredSkinToneIndex = (value: string | number | null): number => { +const getPreferredSkinToneIndex = (value: OnyxEntry): number => { if (value !== null && Number.isInteger(Number(value))) { return Number(value); } diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 3487f05b9c05..ecaf563d59d1 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -1,4 +1,5 @@ import mapValues from 'lodash/mapValues'; +import type {OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; @@ -61,7 +62,7 @@ type OnyxDataWithErrors = { errors?: Errors | null; }; -function getLatestErrorMessage(onyxData: TOnyxData | null): Localize.MaybePhraseKey { +function getLatestErrorMessage(onyxData: OnyxEntry): Localize.MaybePhraseKey { const errors = onyxData?.errors ?? {}; if (Object.keys(errors).length === 0) { @@ -72,8 +73,8 @@ function getLatestErrorMessage(onyxData: T return getErrorMessageWithTranslationData(errors[key]); } -function getLatestErrorMessageField(onyxData: TOnyxData): Errors { - const errors = onyxData.errors ?? {}; +function getLatestErrorMessageField(onyxData: OnyxEntry): Errors { + const errors = onyxData?.errors ?? {}; if (Object.keys(errors).length === 0) { return {}; @@ -88,8 +89,8 @@ type OnyxDataWithErrorFields = { errorFields?: ErrorFields; }; -function getLatestErrorField(onyxData: TOnyxData, fieldName: string): Errors { - const errorsForField = onyxData.errorFields?.[fieldName] ?? {}; +function getLatestErrorField(onyxData: OnyxEntry, fieldName: string): Errors { + const errorsForField = onyxData?.errorFields?.[fieldName] ?? {}; if (Object.keys(errorsForField).length === 0) { return {}; @@ -99,8 +100,8 @@ function getLatestErrorField(onyxData return {[key]: getErrorMessageWithTranslationData(errorsForField[key])}; } -function getEarliestErrorField(onyxData: TOnyxData, fieldName: string): Errors { - const errorsForField = onyxData.errorFields?.[fieldName] ?? {}; +function getEarliestErrorField(onyxData: OnyxEntry, fieldName: string): Errors { + const errorsForField = onyxData?.errorFields?.[fieldName] ?? {}; if (Object.keys(errorsForField).length === 0) { return {}; @@ -113,8 +114,8 @@ function getEarliestErrorField(onyxDa /** * Method used to get the latest error field for any field */ -function getLatestErrorFieldForAnyField(onyxData: TOnyxData): Errors { - const errorFields = onyxData.errorFields ?? {}; +function getLatestErrorFieldForAnyField(onyxData: OnyxEntry): Errors { + const errorFields = onyxData?.errorFields ?? {}; if (Object.keys(errorFields).length === 0) { return {}; @@ -189,9 +190,9 @@ export { getErrorMessageWithTranslationData, getErrorsWithTranslationData, getLatestErrorField, + getLatestErrorFieldForAnyField, getLatestErrorMessage, getLatestErrorMessageField, - getLatestErrorFieldForAnyField, getMicroSecondOnyxError, getMicroSecondOnyxErrorObject, isReceiptError, diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index b4cf4b164a19..98b5bd162fc0 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -21,7 +21,7 @@ type MemberEmailsToAccountIDs = Record; */ function getActivePolicies(policies: OnyxCollection): Policy[] | undefined { return Object.values(policies ?? {}).filter( - (policy): policy is Policy => policy !== null && policy && policy.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && !!policy.name && !!policy.id, + (policy): policy is Policy => !!policy && policy.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && !!policy.name && !!policy.id, ); } diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 32972a81bcb5..95b82f20b810 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -632,7 +632,7 @@ function getLastVisibleMessage(reportID: string, actionsToMerge: OnyxCollection< /** * A helper method to filter out report actions keyed by sequenceNumbers. */ -function filterOutDeprecatedReportActions(reportActions: ReportActions | null): ReportAction[] { +function filterOutDeprecatedReportActions(reportActions: OnyxEntry): ReportAction[] { return Object.entries(reportActions ?? {}) .filter(([key, reportAction]) => !isReportActionDeprecated(reportAction, key)) .map((entry) => entry[1]); @@ -644,7 +644,7 @@ function filterOutDeprecatedReportActions(reportActions: ReportActions | null): * to ensure they will always be displayed in the same order (in case multiple actions have the same timestamp). * This is all handled with getSortedReportActions() which is used by several other methods to keep the code DRY. */ -function getSortedReportActionsForDisplay(reportActions: ReportActions | null | ReportAction[], shouldIncludeInvisibleActions = false): ReportAction[] { +function getSortedReportActionsForDisplay(reportActions: OnyxEntry | ReportAction[], shouldIncludeInvisibleActions = false): ReportAction[] { let filteredReportActions: ReportAction[] = []; if (!reportActions) { return []; @@ -668,7 +668,7 @@ function getSortedReportActionsForDisplay(reportActions: ReportActions | null | * Additionally, archived #admins and #announce do not have the closed report action so we will return null if none is found. * */ -function getLastClosedReportAction(reportActions: ReportActions | null): OnyxEntry { +function getLastClosedReportAction(reportActions: OnyxEntry): OnyxEntry { // If closed report action is not present, return early if (!Object.values(reportActions ?? {}).some((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED)) { return null; @@ -721,7 +721,7 @@ function getLinkedTransactionID(reportActionOrID: string | OnyxEntry { +function getReportAction(reportID: string, reportActionID: string): ReportAction | null { return allReportActions?.[reportID]?.[reportActionID] ?? null; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index f31b4a780c5a..44d0a9b5abb1 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -487,7 +487,7 @@ Onyx.connect({ }, }); -let allPersonalDetails: OnyxCollection; +let allPersonalDetails: OnyxEntry; let allPersonalDetailLogins: string[]; let currentUserPersonalDetails: OnyxEntry; Onyx.connect({ diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index fb18d77c779b..b56c2ebd47df 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -1,4 +1,3 @@ -import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; import type {OnfidoDataWithApplicantID} from '@components/Onfido/types'; @@ -71,7 +70,7 @@ function openPlaidView() { clearPlaid().then(() => ReimbursementAccount.setBankAccountSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID)); } -function setPlaidEvent(eventName: OnyxEntry) { +function setPlaidEvent(eventName: string | null) { Onyx.set(ONYXKEYS.PLAID_CURRENT_EVENT, eventName); } diff --git a/src/libs/actions/FormActions.ts b/src/libs/actions/FormActions.ts index 1fcf9bed6a55..5fe1705d8db3 100644 --- a/src/libs/actions/FormActions.ts +++ b/src/libs/actions/FormActions.ts @@ -24,7 +24,7 @@ function clearErrorFields(formID: OnyxFormKey) { } function setDraftValues(formID: OnyxFormKey, draftValues: NullishDeep>) { - Onyx.merge(`${formID}Draft`, draftValues); + Onyx.merge(`${formID}Draft`, draftValues ?? null); } function clearDraftValues(formID: OnyxFormKey) { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 896b88988818..423b1a4caa04 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1268,7 +1268,7 @@ function getDeleteTrackExpenseInformation( failureData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: transaction, + value: transaction ?? null, }); } @@ -1276,7 +1276,7 @@ function getDeleteTrackExpenseInformation( failureData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: transactionViolations, + value: transactionViolations ?? null, }); } @@ -1355,7 +1355,7 @@ function getMoneyRequestInformation( } if (!chatReport) { - chatReport = ReportUtils.getChatByParticipants([payerAccountID]); + chatReport = ReportUtils.getChatByParticipants([payerAccountID]) ?? null; } // If we still don't have a report, it likely doens't exist and we need to build an optimistic one @@ -4685,7 +4685,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: transaction, + value: transaction ?? null, }, ]; @@ -4693,7 +4693,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor failureData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: transactionViolations, + value: transactionViolations ?? null, }); } @@ -5747,7 +5747,7 @@ function detachReceipt(transactionID: string) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: transaction, + value: transaction ?? null, }, ]; diff --git a/src/libs/actions/OnyxUpdates.ts b/src/libs/actions/OnyxUpdates.ts index bb486d97b33b..33d283ec1262 100644 --- a/src/libs/actions/OnyxUpdates.ts +++ b/src/libs/actions/OnyxUpdates.ts @@ -1,4 +1,4 @@ -import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; +import type {OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {Merge} from 'type-fest'; import Log from '@libs/Log'; @@ -13,7 +13,7 @@ import * as QueuedOnyxUpdates from './QueuedOnyxUpdates'; // This key needs to be separate from ONYXKEYS.ONYX_UPDATES_FROM_SERVER so that it can be updated without triggering the callback when the server IDs are updated. If that // callback were triggered it would lead to duplicate processing of server updates. -let lastUpdateIDAppliedToClient: OnyxEntry = 0; +let lastUpdateIDAppliedToClient: number | null = 0; Onyx.connect({ key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, callback: (val) => (lastUpdateIDAppliedToClient = val), @@ -157,4 +157,4 @@ function applyOnyxUpdatesReliably(updates: OnyxUpdatesFromServer) { } // eslint-disable-next-line import/prefer-default-export -export {saveUpdateInformation, doesClientNeedToBeUpdated, apply, applyOnyxUpdatesReliably}; +export {apply, applyOnyxUpdatesReliably, doesClientNeedToBeUpdated, saveUpdateInformation}; diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index fffc992746d9..ed375bcad972 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -257,7 +257,7 @@ Onyx.connect({ * Stores in Onyx the policy ID of the last workspace that was accessed by the user */ function updateLastAccessedWorkspace(policyID: OnyxEntry) { - Onyx.set(ONYXKEYS.LAST_ACCESSED_WORKSPACE_POLICY_ID, policyID); + Onyx.set(ONYXKEYS.LAST_ACCESSED_WORKSPACE_POLICY_ID, policyID ?? null); } /** diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index f599208ff915..ef33325053e5 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -754,8 +754,8 @@ function openReport( ); // Add optimistic personal details for new participants - const optimisticPersonalDetails: OnyxCollection = {}; - const settledPersonalDetails: OnyxCollection = {}; + const optimisticPersonalDetails: OnyxEntry = {}; + const settledPersonalDetails: OnyxEntry = {}; participantLoginList.forEach((login, index) => { const accountID = newReportObject?.participantAccountIDs?.[index]; diff --git a/src/libs/migrations/RenameReceiptFilename.ts b/src/libs/migrations/RenameReceiptFilename.ts index b867024fc74e..100b279c950f 100644 --- a/src/libs/migrations/RenameReceiptFilename.ts +++ b/src/libs/migrations/RenameReceiptFilename.ts @@ -1,5 +1,5 @@ import Onyx from 'react-native-onyx'; -import type {NullishDeep, OnyxCollection} from 'react-native-onyx'; +import type {NullishDeep, OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Log from '@libs/Log'; import ONYXKEYS from '@src/ONYXKEYS'; import type Transaction from '@src/types/onyx/Transaction'; @@ -24,7 +24,7 @@ export default function () { return resolve(); } - const transactionsWithReceipt: Array = Object.values(transactions).filter((transaction) => transaction?.receiptFilename); + const transactionsWithReceipt: Array> = Object.values(transactions).filter((transaction) => transaction?.receiptFilename); if (!transactionsWithReceipt?.length) { Log.info('[Migrate Onyx] Skipped migration RenameReceiptFilename because there were no transactions with the receiptFilename property'); return resolve(); diff --git a/src/libs/migrations/TransactionBackupsToCollection.ts b/src/libs/migrations/TransactionBackupsToCollection.ts index 407bc70e1f38..5b6865ca6fe0 100644 --- a/src/libs/migrations/TransactionBackupsToCollection.ts +++ b/src/libs/migrations/TransactionBackupsToCollection.ts @@ -1,4 +1,4 @@ -import type {OnyxCollection} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import Log from '@libs/Log'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -30,7 +30,7 @@ export default function (): Promise { // Find all the transaction backups available Object.keys(transactions).forEach((transactionOnyxKey: string) => { - const transaction: Transaction | null = transactions[transactionOnyxKey]; + const transaction: OnyxEntry = transactions[transactionOnyxKey]; // Determine whether or not the transaction is a backup if (transactionOnyxKey.endsWith('-backup') && transaction) { diff --git a/src/pages/GroupChatNameEditPage.tsx b/src/pages/GroupChatNameEditPage.tsx index 05d179fa552a..742fed5c61a6 100644 --- a/src/pages/GroupChatNameEditPage.tsx +++ b/src/pages/GroupChatNameEditPage.tsx @@ -1,5 +1,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useMemo} from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -24,7 +25,7 @@ import type NewGroupChatDraft from '@src/types/onyx/NewGroupChatDraft'; import type {Errors} from '@src/types/onyx/OnyxCommon'; type GroupChatNameEditPageOnyxProps = { - groupChatDraft: NewGroupChatDraft | null; + groupChatDraft: OnyxEntry; }; type GroupChatNameEditPageProps = StackScreenProps & GroupChatNameEditPageOnyxProps; diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 8137bb0e8515..cc9bfc7aa5d7 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -2,6 +2,7 @@ import isEmpty from 'lodash/isEmpty'; import reject from 'lodash/reject'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import KeyboardAvoidingView from '@components/KeyboardAvoidingView'; @@ -31,6 +32,7 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Beta} from '@src/types/onyx'; import type {SelectedParticipant} from '@src/types/onyx/NewGroupChatDraft'; type NewChatPageProps = { @@ -55,7 +57,7 @@ function useOptions({isGroupChat}: NewChatPageProps) { const filteredOptions = OptionsListUtils.getFilteredOptions( listOptions.reports ?? [], listOptions.personalDetails ?? [], - betas ?? [], + (betas ?? []) as OnyxEntry, debouncedSearchTerm, selectedOptions, isGroupChat ? excludedGroupEmails : [], diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.tsx b/src/pages/PrivateNotes/PrivateNotesEditPage.tsx index 7d0b8fff8e41..1d5efe45faf8 100644 --- a/src/pages/PrivateNotes/PrivateNotesEditPage.tsx +++ b/src/pages/PrivateNotes/PrivateNotesEditPage.tsx @@ -5,7 +5,7 @@ import Str from 'expensify-common/lib/str'; import lodashDebounce from 'lodash/debounce'; import React, {useCallback, useMemo, useRef, useState} from 'react'; import {Keyboard} from 'react-native'; -import type {OnyxCollection} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -30,12 +30,12 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/PrivateNotesForm'; -import type {PersonalDetails, Report} from '@src/types/onyx'; +import type {PersonalDetailsList, Report} from '@src/types/onyx'; import type {Note} from '@src/types/onyx/Report'; type PrivateNotesEditPageOnyxProps = { /** All of the personal details for everyone */ - personalDetailsList: OnyxCollection; + personalDetailsList: OnyxEntry; }; type PrivateNotesEditPageProps = WithReportAndPrivateNotesOrNotFoundProps & diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.tsx b/src/pages/PrivateNotes/PrivateNotesListPage.tsx index 1893f81da2fe..cf3ce4c36b53 100644 --- a/src/pages/PrivateNotes/PrivateNotesListPage.tsx +++ b/src/pages/PrivateNotes/PrivateNotesListPage.tsx @@ -1,6 +1,6 @@ import React, {useMemo} from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import type {OnyxCollection} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; @@ -15,11 +15,11 @@ import withReportAndPrivateNotesOrNotFound from '@pages/home/report/withReportAn import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetails, Report} from '@src/types/onyx'; +import type {PersonalDetailsList, Report} from '@src/types/onyx'; type PrivateNotesListPageOnyxProps = { /** All of the personal details for everyone */ - personalDetailsList: OnyxCollection; + personalDetailsList: OnyxEntry; }; type PrivateNotesListPageProps = WithReportAndPrivateNotesOrNotFoundProps & diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx index a83e18d119c9..97a8caaef692 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx @@ -1,6 +1,7 @@ import Str from 'expensify-common/lib/str'; import React, {useCallback} from 'react'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; @@ -26,7 +27,7 @@ type BankAccountValidationFormProps = { requiresTwoFactorAuth: boolean; /** The policy which the user has access to and which the report is tied to */ - policy: Policy | null; + policy: OnyxEntry; }; type AmountValues = { diff --git a/src/pages/ReimbursementAccount/utils/getValuesForBeneficialOwner.ts b/src/pages/ReimbursementAccount/utils/getValuesForBeneficialOwner.ts index 3733a6727c54..b564b8f325ee 100644 --- a/src/pages/ReimbursementAccount/utils/getValuesForBeneficialOwner.ts +++ b/src/pages/ReimbursementAccount/utils/getValuesForBeneficialOwner.ts @@ -1,3 +1,4 @@ +import type {OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import type {ReimbursementAccountForm} from '@src/types/form'; @@ -12,7 +13,7 @@ type BeneficialOwnerValues = { zipCode: string; }; -function getValuesForBeneficialOwner(beneficialOwnerBeingModifiedID: string, reimbursementAccountDraft: ReimbursementAccountForm | null): BeneficialOwnerValues { +function getValuesForBeneficialOwner(beneficialOwnerBeingModifiedID: string, reimbursementAccountDraft: OnyxEntry): BeneficialOwnerValues { if (!reimbursementAccountDraft) { return { firstName: '', diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 0646f37f9b26..54c8747567f4 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -2,7 +2,7 @@ import {useRoute} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; import React, {useEffect, useMemo} from 'react'; import {View} from 'react-native'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import AvatarWithImagePicker from '@components/AvatarWithImagePicker'; @@ -53,7 +53,7 @@ type ReportDetailsPageMenuItem = { type ReportDetailsPageOnyxProps = { /** Personal details of all the users */ - personalDetails: OnyxCollection; + personalDetails: OnyxEntry; /** Session info for the currently logged in user. */ session: OnyxEntry; diff --git a/src/pages/home/sidebar/ProfileAvatarWithIndicator.tsx b/src/pages/home/sidebar/ProfileAvatarWithIndicator.tsx index e7726fb89537..dd12963a7cde 100644 --- a/src/pages/home/sidebar/ProfileAvatarWithIndicator.tsx +++ b/src/pages/home/sidebar/ProfileAvatarWithIndicator.tsx @@ -16,8 +16,7 @@ type ProfileAvatarWithIndicatorProps = { function ProfileAvatarWithIndicator({isSelected = false}: ProfileAvatarWithIndicatorProps) { const styles = useThemeStyles(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const [isLoadingOnyxValue] = useOnyx(ONYXKEYS.IS_LOADING_APP); - const isLoading = isLoadingOnyxValue ?? true; + const [isLoading = true] = useOnyx(ONYXKEYS.IS_LOADING_APP); return ( diff --git a/src/types/utils/isLoadingOnyxValue.ts b/src/types/utils/isLoadingOnyxValue.ts index 052c97ad40ef..7d5bfa88ba2e 100644 --- a/src/types/utils/isLoadingOnyxValue.ts +++ b/src/types/utils/isLoadingOnyxValue.ts @@ -1,6 +1,6 @@ -import type {OnyxKey, UseOnyxResult} from 'react-native-onyx'; +import type {ResultMetadata} from 'react-native-onyx'; -function isLoadingOnyxValue(...results: Array[1]>): boolean { +function isLoadingOnyxValue(...results: ResultMetadata[]): boolean { return results.some((result) => result.status === 'loading'); } diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index c8c74d4198ab..32727518769a 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -464,7 +464,7 @@ describe('actions/IOU', () => { fetch.pause(); return ( Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport) - .then(() => Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`, iouReport)) + .then(() => Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`, iouReport ?? null)) .then(() => Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, { [createdAction.reportActionID]: createdAction, @@ -785,7 +785,7 @@ describe('actions/IOU', () => { .then( () => new Promise((resolve) => { - ReportActions.clearAllRelatedReportActionErrors(iouReportID ?? '', iouAction); + ReportActions.clearAllRelatedReportActionErrors(iouReportID ?? '', iouAction ?? null); resolve(); }), ) From 35007324b5bbd61f2b6304708808183b5c749d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Fri, 19 Apr 2024 09:22:19 +0100 Subject: [PATCH 02/18] Bump TS version to match Onyx's one --- package-lock.json | 7 ++++--- package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 52a975e3a83e..096adba2c0ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -239,7 +239,7 @@ "ts-jest": "^29.1.2", "ts-node": "^10.9.2", "type-fest": "^4.10.2", - "typescript": "^5.3.2", + "typescript": "^5.4.5", "wait-port": "^0.2.9", "webpack": "^5.76.0", "webpack-bundle-analyzer": "^4.5.0", @@ -35928,9 +35928,10 @@ } }, "node_modules/typescript": { - "version": "5.3.3", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "devOptional": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 1cef7d94fcba..a9aa3c5ba700 100644 --- a/package.json +++ b/package.json @@ -290,7 +290,7 @@ "ts-jest": "^29.1.2", "ts-node": "^10.9.2", "type-fest": "^4.10.2", - "typescript": "^5.3.2", + "typescript": "^5.4.5", "wait-port": "^0.2.9", "webpack": "^5.76.0", "webpack-bundle-analyzer": "^4.5.0", From 90b78a6a85d6364227f3ba9f5ec80f3ad3ed484b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Fri, 19 Apr 2024 09:22:28 +0100 Subject: [PATCH 03/18] Typing fixes --- src/components/KeyboardAvoidingView/index.ios.tsx | 2 +- src/components/KeyboardAvoidingView/index.tsx | 2 +- src/components/KeyboardAvoidingView/types.ts | 5 +++-- src/libs/Pusher/pusher.ts | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/KeyboardAvoidingView/index.ios.tsx b/src/components/KeyboardAvoidingView/index.ios.tsx index a7cd767377ef..171210eab7ac 100644 --- a/src/components/KeyboardAvoidingView/index.ios.tsx +++ b/src/components/KeyboardAvoidingView/index.ios.tsx @@ -3,7 +3,7 @@ */ import React from 'react'; import {KeyboardAvoidingView as KeyboardAvoidingViewComponent} from 'react-native'; -import type KeyboardAvoidingViewProps from './types'; +import type {KeyboardAvoidingViewProps} from './types'; function KeyboardAvoidingView(props: KeyboardAvoidingViewProps) { // eslint-disable-next-line react/jsx-props-no-spreading diff --git a/src/components/KeyboardAvoidingView/index.tsx b/src/components/KeyboardAvoidingView/index.tsx index 09ec21e5b219..c0882ae1e9cc 100644 --- a/src/components/KeyboardAvoidingView/index.tsx +++ b/src/components/KeyboardAvoidingView/index.tsx @@ -3,7 +3,7 @@ */ import React from 'react'; import {View} from 'react-native'; -import type KeyboardAvoidingViewProps from './types'; +import type {KeyboardAvoidingViewProps} from './types'; function KeyboardAvoidingView(props: KeyboardAvoidingViewProps) { const {behavior, contentContainerStyle, enabled, keyboardVerticalOffset, ...rest} = props; diff --git a/src/components/KeyboardAvoidingView/types.ts b/src/components/KeyboardAvoidingView/types.ts index 48d354e8b53f..2c1ef64ced8f 100644 --- a/src/components/KeyboardAvoidingView/types.ts +++ b/src/components/KeyboardAvoidingView/types.ts @@ -1,3 +1,4 @@ -import {KeyboardAvoidingViewProps} from 'react-native'; +import type {KeyboardAvoidingViewProps} from 'react-native'; -export default KeyboardAvoidingViewProps; +// eslint-disable-next-line import/prefer-default-export +export type {KeyboardAvoidingViewProps}; diff --git a/src/libs/Pusher/pusher.ts b/src/libs/Pusher/pusher.ts index 48c5e5c1409f..e71ab96066e8 100644 --- a/src/libs/Pusher/pusher.ts +++ b/src/libs/Pusher/pusher.ts @@ -166,7 +166,7 @@ function bindEventToChannel(channel: Channel let data; try { - data = isObject(eventData) ? eventData : JSON.parse(eventData); + data = isObject(eventData) ? eventData : JSON.parse(eventData as string); } catch (err) { Log.alert('[Pusher] Unable to parse single JSON event data from Pusher', {error: err, eventData}); return; From 6d3d918f74bdb5f74315bce1204403ad6b918129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Thu, 25 Apr 2024 11:33:03 +0100 Subject: [PATCH 04/18] lint fix --- src/libs/actions/Report.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 4f4af6304dcb..a0fa7fb1c081 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -82,7 +82,6 @@ import INPUT_IDS from '@src/types/form/NewRoomForm'; import type { InvitedEmailsToAccountIDs, NewGroupChatDraft, - PersonalDetails, PersonalDetailsList, PolicyReportField, QuickAction, From d64780ff036be679532f5d4cac273cc7f9e19790 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 15:12:32 +0200 Subject: [PATCH 05/18] bump onyx --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 58f3d860148f..a7f3aa8edf79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,7 +100,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.32", + "react-native-onyx": "^2.0.40", "react-native-pager-view": "6.2.3", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", @@ -31431,9 +31431,9 @@ } }, "node_modules/react-native-onyx": { - "version": "2.0.32", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.32.tgz", - "integrity": "sha512-tB9wqMJGTLOYfrfplRP+9aq5JdD8w/hV/OZsMAVH+ewbE1zLY8OymUsAsIFdF1v+cB8HhehP569JVLZmhm6bsg==", + "version": "2.0.40", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.40.tgz", + "integrity": "sha512-p4GDm561i1HX4QPSz3TjTXwzgCTZepu0I2zWJnNZ7T7cs6WMSSBH5XRJQn2McuKNssuCuBD4MxB2zOqIkD191A==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", diff --git a/package.json b/package.json index 234879f89574..55dacc44a156 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.32", + "react-native-onyx": "^2.0.40", "react-native-pager-view": "6.2.3", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", From 657be972726e04a488e93d6d8f4106f8503cd509 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 15:12:43 +0200 Subject: [PATCH 06/18] fix: country not updated in address form --- src/components/AddressForm.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/AddressForm.tsx b/src/components/AddressForm.tsx index 9ad4643e834a..296ecce7d092 100644 --- a/src/components/AddressForm.tsx +++ b/src/components/AddressForm.tsx @@ -4,7 +4,6 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import type {MaybePhraseKey} from '@libs/Localize'; -import Navigation from '@libs/Navigation/Navigation'; import * as ValidationUtils from '@libs/ValidationUtils'; import CONST from '@src/CONST'; import type {Country} from '@src/CONST'; @@ -149,8 +148,6 @@ function AddressForm({ label={translate('common.addressLine', {lineNumber: 1})} onValueChange={(data: unknown, key: unknown) => { onAddressChanged(data, key); - // This enforces the country selector to use the country from address instead of the country from URL - Navigation.setParams({country: undefined}); }} defaultValue={street1} renamedInputKeys={{ From 307b300d2efa568a626d468c81049454e8fc8c1d Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 15:12:58 +0200 Subject: [PATCH 07/18] fix: improve naming and casting of variables --- .../Profile/PersonalDetails/AddressPage.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.tsx b/src/pages/settings/Profile/PersonalDetails/AddressPage.tsx index fcb018348b72..91a8b94537ab 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.tsx @@ -70,31 +70,31 @@ function AddressPage({privatePersonalDetails, route, isLoadingApp = true}: Addre }, [address]); const handleAddressChange = useCallback((value: unknown, key: unknown) => { - const countryValue = value as Country | ''; - const addressKey = key as keyof Address; + const addressPart = value as string; + const addressPartKey = key as keyof Address; - if (addressKey !== 'country' && addressKey !== 'state' && addressKey !== 'city' && addressKey !== 'zipPostCode') { + if (addressPartKey !== 'country' && addressPartKey !== 'state' && addressPartKey !== 'city' && addressPartKey !== 'zipPostCode') { return; } - if (addressKey === 'country') { - setCurrentCountry(countryValue); + if (addressPartKey === 'country') { + setCurrentCountry(addressPart as Country | ''); setState(''); setCity(''); setZipcode(''); return; } - if (addressKey === 'state') { - setState(countryValue); + if (addressPartKey === 'state') { + setState(addressPart); setCity(''); setZipcode(''); return; } - if (addressKey === 'city') { - setCity(countryValue); + if (addressPartKey === 'city') { + setCity(addressPart); setZipcode(''); return; } - setZipcode(countryValue); + setZipcode(addressPart); }, []); useEffect(() => { From 93252629afa1c8c11afe3b1247dfcae4df323a56 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 15:25:13 +0200 Subject: [PATCH 08/18] set strict version --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a7f3aa8edf79..60a5e18d3274 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,7 +100,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "^2.0.40", + "react-native-onyx": "2.0.40", "react-native-pager-view": "6.2.3", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", diff --git a/package.json b/package.json index 55dacc44a156..9716243e6ece 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "^2.0.40", + "react-native-onyx": "2.0.40", "react-native-pager-view": "6.2.3", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", From 408e0b093f0c695bbf090ebf694dddb6f07a089e Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 15:38:33 +0200 Subject: [PATCH 09/18] fix: IOUTest types --- tests/actions/IOUTest.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 45bdc5fe743a..ae3a7c48bee2 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -22,6 +22,7 @@ import type {IOUMessage, OriginalMessageIOU} from '@src/types/onyx/OriginalMessa import type {ReportActionBase} from '@src/types/onyx/ReportAction'; import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import type NonUndefined from '@src/types/utils/NonUndefined'; import PusherHelper from '../utils/PusherHelper'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; @@ -435,7 +436,7 @@ describe('actions/IOU', () => { merchant: '', reportID: '', }; - let iouReport: OnyxEntry = { + let iouReport: NonUndefined> = { reportID: iouReportID, chatReportID, type: CONST.REPORT.TYPE.IOU, @@ -444,7 +445,7 @@ describe('actions/IOU', () => { currency: CONST.CURRENCY.USD, total: existingTransaction.amount, }; - const iouAction: OnyxEntry = { + const iouAction: NonUndefined> = { reportActionID: NumberUtils.rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.IOU, actorAccountID: RORY_ACCOUNT_ID, From 883e3e16781956a7785531dc6aab038f97f6432d Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 15:39:12 +0200 Subject: [PATCH 10/18] fix: more type errors --- src/libs/ErrorUtils.ts | 2 +- src/libs/actions/ReportActions.ts | 4 ++-- src/types/utils/NonUndefined.ts | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 src/types/utils/NonUndefined.ts diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 3487f05b9c05..3fab727a83f5 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -61,7 +61,7 @@ type OnyxDataWithErrors = { errors?: Errors | null; }; -function getLatestErrorMessage(onyxData: TOnyxData | null): Localize.MaybePhraseKey { +function getLatestErrorMessage(onyxData: TOnyxData | null | undefined): Localize.MaybePhraseKey { const errors = onyxData?.errors ?? {}; if (Object.keys(errors).length === 0) { diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts index 217dd0b12100..4fc72bae1e7d 100644 --- a/src/libs/actions/ReportActions.ts +++ b/src/libs/actions/ReportActions.ts @@ -71,11 +71,11 @@ Onyx.connect({ }); /** - * + * ignore: `undefined` means we want to check both parent and children report actions ignore: `parent` or `child` means we want to ignore checking parent or child report actions because they've been previously checked */ -function clearAllRelatedReportActionErrors(reportID: string, reportAction: ReportAction | null, ignore?: IgnoreDirection, keys?: string[]) { +function clearAllRelatedReportActionErrors(reportID: string, reportAction: ReportAction | null | undefined, ignore?: IgnoreDirection, keys?: string[]) { const errorKeys = keys ?? Object.keys(reportAction?.errors ?? {}); if (!reportAction || errorKeys.length === 0) { return; diff --git a/src/types/utils/NonUndefined.ts b/src/types/utils/NonUndefined.ts new file mode 100644 index 000000000000..e4b76638f80d --- /dev/null +++ b/src/types/utils/NonUndefined.ts @@ -0,0 +1,6 @@ +/** + * Utility type that excludes `undefined` from the type `TValue`. + */ +type NonUndefined = TValue extends undefined ? never : TValue; + +export default NonUndefined; From f2d293b76a305e28c68b2b3e6b29b19542914cee Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 16:05:14 +0200 Subject: [PATCH 11/18] fix: personal details list typings --- src/components/AvatarWithDisplayName.tsx | 6 +++--- src/libs/ReportUtils.ts | 8 ++++---- src/libs/actions/Report.ts | 5 ++--- src/pages/PrivateNotes/PrivateNotesEditPage.tsx | 6 +++--- src/pages/PrivateNotes/PrivateNotesListPage.tsx | 6 +++--- src/pages/ReportDetailsPage.tsx | 4 ++-- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index 8942bf97a7dd..156c27abbc9d 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -1,6 +1,6 @@ import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -12,7 +12,7 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetails, Policy, Report, ReportActions} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, Policy, Report, ReportActions} from '@src/types/onyx'; import DisplayNames from './DisplayNames'; import MultipleAvatars from './MultipleAvatars'; import ParentNavigationSubtitle from './ParentNavigationSubtitle'; @@ -25,7 +25,7 @@ type AvatarWithDisplayNamePropsWithOnyx = { parentReportActions: OnyxEntry; /** Personal details of all users */ - personalDetails: OnyxCollection; + personalDetails: OnyxEntry; }; type AvatarWithDisplayNameProps = AvatarWithDisplayNamePropsWithOnyx & { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b1444d33ccb7..1db23ca2a39a 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -507,7 +507,7 @@ Onyx.connect({ }, }); -let allPersonalDetails: OnyxCollection; +let allPersonalDetails: OnyxEntry; let allPersonalDetailLogins: string[]; let currentUserPersonalDetails: OnyxEntry; Onyx.connect({ @@ -1629,7 +1629,7 @@ function getReportRecipientAccountIDs(report: OnyxEntry, currentLoginAcc /** * Whether the time row should be shown for a report. */ -function canShowReportRecipientLocalTime(personalDetails: OnyxCollection, report: OnyxEntry, accountID: number): boolean { +function canShowReportRecipientLocalTime(personalDetails: OnyxEntry, report: OnyxEntry, accountID: number): boolean { const reportRecipientAccountIDs = getReportRecipientAccountIDs(report, accountID); const hasMultipleParticipants = reportRecipientAccountIDs.length > 1; const reportRecipient = personalDetails?.[reportRecipientAccountIDs[0]]; @@ -1713,7 +1713,7 @@ function getDefaultGroupAvatar(reportID?: string): IconAsset { * Returns the appropriate icons for the given chat report using the stored personalDetails. * The Avatar sources can be URLs or Icon components according to the chat type. */ -function getIconsForParticipants(participants: number[], personalDetails: OnyxCollection): Icon[] { +function getIconsForParticipants(participants: number[], personalDetails: OnyxEntry): Icon[] { const participantDetails: ParticipantDetails[] = []; const participantsList = participants || []; @@ -1898,7 +1898,7 @@ function getParticipants(reportID: string) { */ function getIcons( report: OnyxEntry, - personalDetails: OnyxCollection, + personalDetails: OnyxEntry, defaultIcon: UserUtils.AvatarSource | null = null, defaultName = '', defaultAccountID = -1, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index d4ced6acd60d..7fe4b8f2470a 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -85,7 +85,6 @@ import INPUT_IDS from '@src/types/form/NewRoomForm'; import type { InvitedEmailsToAccountIDs, NewGroupChatDraft, - PersonalDetails, PersonalDetailsList, PolicyReportField, QuickAction, @@ -864,8 +863,8 @@ function openReport( ); // Add optimistic personal details for new participants - const optimisticPersonalDetails: OnyxCollection = {}; - const settledPersonalDetails: OnyxCollection = {}; + const optimisticPersonalDetails: OnyxEntry = {}; + const settledPersonalDetails: OnyxEntry = {}; participantLoginList.forEach((login, index) => { const accountID = newReportObject?.participantAccountIDs?.[index]; diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.tsx b/src/pages/PrivateNotes/PrivateNotesEditPage.tsx index f9560edf7486..aebdb774a8cc 100644 --- a/src/pages/PrivateNotes/PrivateNotesEditPage.tsx +++ b/src/pages/PrivateNotes/PrivateNotesEditPage.tsx @@ -5,7 +5,7 @@ import Str from 'expensify-common/lib/str'; import lodashDebounce from 'lodash/debounce'; import React, {useCallback, useMemo, useRef, useState} from 'react'; import {Keyboard} from 'react-native'; -import type {OnyxCollection} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -31,12 +31,12 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/PrivateNotesForm'; -import type {PersonalDetails, Report} from '@src/types/onyx'; +import type {PersonalDetailsList, Report} from '@src/types/onyx'; import type {Note} from '@src/types/onyx/Report'; type PrivateNotesEditPageOnyxProps = { /** All of the personal details for everyone */ - personalDetailsList: OnyxCollection; + personalDetailsList: OnyxEntry; }; type PrivateNotesEditPageProps = WithReportAndPrivateNotesOrNotFoundProps & diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.tsx b/src/pages/PrivateNotes/PrivateNotesListPage.tsx index 1893f81da2fe..cf3ce4c36b53 100644 --- a/src/pages/PrivateNotes/PrivateNotesListPage.tsx +++ b/src/pages/PrivateNotes/PrivateNotesListPage.tsx @@ -1,6 +1,6 @@ import React, {useMemo} from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import type {OnyxCollection} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; @@ -15,11 +15,11 @@ import withReportAndPrivateNotesOrNotFound from '@pages/home/report/withReportAn import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetails, Report} from '@src/types/onyx'; +import type {PersonalDetailsList, Report} from '@src/types/onyx'; type PrivateNotesListPageOnyxProps = { /** All of the personal details for everyone */ - personalDetailsList: OnyxCollection; + personalDetailsList: OnyxEntry; }; type PrivateNotesListPageProps = WithReportAndPrivateNotesOrNotFoundProps & diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index ca66a0e97bb5..a4d7c6eb7a22 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -2,7 +2,7 @@ import {useRoute} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; import React, {useEffect, useMemo} from 'react'; import {View} from 'react-native'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import AvatarWithImagePicker from '@components/AvatarWithImagePicker'; @@ -53,7 +53,7 @@ type ReportDetailsPageMenuItem = { type ReportDetailsPageOnyxProps = { /** Personal details of all the users */ - personalDetails: OnyxCollection; + personalDetails: OnyxEntry; /** Session info for the currently logged in user. */ session: OnyxEntry; From 10e3ab07d4fad7c46923a375783d20557a98f0c7 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 16:33:46 +0200 Subject: [PATCH 12/18] update onyx --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 60a5e18d3274..d289b7b1679f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,7 +100,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.40", + "react-native-onyx": "2.0.41", "react-native-pager-view": "6.2.3", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", @@ -31431,9 +31431,9 @@ } }, "node_modules/react-native-onyx": { - "version": "2.0.40", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.40.tgz", - "integrity": "sha512-p4GDm561i1HX4QPSz3TjTXwzgCTZepu0I2zWJnNZ7T7cs6WMSSBH5XRJQn2McuKNssuCuBD4MxB2zOqIkD191A==", + "version": "2.0.41", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.41.tgz", + "integrity": "sha512-33r0sVBq7MV/GZwRneRt81uxgW8x3YG75VNJvThycB/dkCnGCfbxoVkZADVH3ET3jzfFXy9wnS06sZnZp78zMQ==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", diff --git a/package.json b/package.json index 9716243e6ece..bf7442e72da9 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.40", + "react-native-onyx": "2.0.41", "react-native-pager-view": "6.2.3", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", From 692c071a84d644b6e635452cf1165f3ab1c1a3c5 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 16:34:04 +0200 Subject: [PATCH 13/18] fix: more ts errors --- src/languages/types.ts | 6 +++--- .../utils/getValuesForBeneficialOwner.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/languages/types.ts b/src/languages/types.ts index e2e7e26e696b..7fb8c6473e9c 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -40,15 +40,15 @@ type LocalTimeParams = { }; type EditActionParams = { - action: ReportAction | null; + action: ReportAction | null | undefined; }; type DeleteActionParams = { - action: ReportAction | null; + action: ReportAction | null | undefined; }; type DeleteConfirmationParams = { - action: ReportAction | null; + action: ReportAction | null | undefined; }; type BeginningOfChatHistoryDomainRoomPartOneParams = { diff --git a/src/pages/ReimbursementAccount/utils/getValuesForBeneficialOwner.ts b/src/pages/ReimbursementAccount/utils/getValuesForBeneficialOwner.ts index 3733a6727c54..47096d856316 100644 --- a/src/pages/ReimbursementAccount/utils/getValuesForBeneficialOwner.ts +++ b/src/pages/ReimbursementAccount/utils/getValuesForBeneficialOwner.ts @@ -12,7 +12,7 @@ type BeneficialOwnerValues = { zipCode: string; }; -function getValuesForBeneficialOwner(beneficialOwnerBeingModifiedID: string, reimbursementAccountDraft: ReimbursementAccountForm | null): BeneficialOwnerValues { +function getValuesForBeneficialOwner(beneficialOwnerBeingModifiedID: string, reimbursementAccountDraft: ReimbursementAccountForm | null | undefined): BeneficialOwnerValues { if (!reimbursementAccountDraft) { return { firstName: '', From d722f2771aa4c3909d443e2ea68ee1b115ff66a5 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 16:42:09 +0200 Subject: [PATCH 14/18] fix: more ts issues --- src/components/KeyboardAvoidingView/types.ts | 4 +++- src/libs/EmojiUtils.ts | 2 +- src/libs/ReportActionsUtils.ts | 2 +- src/libs/ReportUtils.ts | 2 +- src/pages/GroupChatNameEditPage.tsx | 2 +- .../components/BankAccountValidationForm.tsx | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/KeyboardAvoidingView/types.ts b/src/components/KeyboardAvoidingView/types.ts index 48d354e8b53f..7045ed152dc0 100644 --- a/src/components/KeyboardAvoidingView/types.ts +++ b/src/components/KeyboardAvoidingView/types.ts @@ -1,3 +1,5 @@ -import {KeyboardAvoidingViewProps} from 'react-native'; +import type {KeyboardAvoidingViewProps as KeyboardAvoidingViewPropsRN} from 'react-native'; + +type KeyboardAvoidingViewProps = KeyboardAvoidingViewPropsRN; export default KeyboardAvoidingViewProps; diff --git a/src/libs/EmojiUtils.ts b/src/libs/EmojiUtils.ts index 3b189dbb084f..6fc80b3612f2 100644 --- a/src/libs/EmojiUtils.ts +++ b/src/libs/EmojiUtils.ts @@ -431,7 +431,7 @@ function suggestEmojis(text: string, lang: Locale, limit: number = CONST.AUTO_CO /** * Retrieve preferredSkinTone as Number to prevent legacy 'default' String value */ -const getPreferredSkinToneIndex = (value: string | number | null): number => { +const getPreferredSkinToneIndex = (value: string | number | null | undefined): number => { if (value !== null && Number.isInteger(Number(value))) { return Number(value); } diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 906a2963baa8..dc52d7c4116d 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -656,7 +656,7 @@ function filterOutDeprecatedReportActions(reportActions: ReportActions | null): * to ensure they will always be displayed in the same order (in case multiple actions have the same timestamp). * This is all handled with getSortedReportActions() which is used by several other methods to keep the code DRY. */ -function getSortedReportActionsForDisplay(reportActions: ReportActions | null | ReportAction[], shouldIncludeInvisibleActions = false): ReportAction[] { +function getSortedReportActionsForDisplay(reportActions: ReportActions | ReportAction[] | null | undefined, shouldIncludeInvisibleActions = false): ReportAction[] { let filteredReportActions: ReportAction[] = []; if (!reportActions) { return []; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 1db23ca2a39a..84c87ee9325e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3367,7 +3367,7 @@ function getParsedComment(text: string, parsingDetails?: ParsingDetails): string }); return text.length <= CONST.MAX_MARKUP_LENGTH - ? parser.replace(textWithMention, {shouldEscapeText: parsingDetails?.shouldEscapeText, disabledRules: isGroupPolicyReport ? [] : ['reportMentions']}) + ? parser.replace(textWithMention, {shouldEscapeText: parsingDetails?.shouldEscapeText, filterRules: isGroupPolicyReport ? [] : ['reportMentions']}) : lodashEscape(text); } diff --git a/src/pages/GroupChatNameEditPage.tsx b/src/pages/GroupChatNameEditPage.tsx index 87218fbb89cd..c1fea7049084 100644 --- a/src/pages/GroupChatNameEditPage.tsx +++ b/src/pages/GroupChatNameEditPage.tsx @@ -24,7 +24,7 @@ import type NewGroupChatDraft from '@src/types/onyx/NewGroupChatDraft'; import type {Errors} from '@src/types/onyx/OnyxCommon'; type GroupChatNameEditPageOnyxProps = { - groupChatDraft: NewGroupChatDraft | null; + groupChatDraft: NewGroupChatDraft | null | undefined; }; type GroupChatNameEditPageProps = StackScreenProps & GroupChatNameEditPageOnyxProps; diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx index a83e18d119c9..025874574185 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx @@ -26,7 +26,7 @@ type BankAccountValidationFormProps = { requiresTwoFactorAuth: boolean; /** The policy which the user has access to and which the report is tied to */ - policy: Policy | null; + policy: Policy | null | undefined; }; type AmountValues = { From f5d18d807cc1fd403cb96755e6e9ccc0b2541415 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 13 May 2024 18:07:41 +0200 Subject: [PATCH 15/18] Update src/hooks/useReportIDs.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Henriques --- src/hooks/useReportIDs.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index 050dc585a03d..c1503595fa24 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -133,8 +133,7 @@ function ReportIDsContextProvider({ SidebarUtils.getOrderedReportIDs( currentReportID ?? null, chatReports, - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - betas as OnyxEntry, + betas, policies, priorityMode, allReportActions, From bcc3f964fb449d72af45ede695da5901c1ce8c6d Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Tue, 14 May 2024 13:13:42 +0200 Subject: [PATCH 16/18] revert invalid change --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a5643cbdc5b7..74066b96ccd2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3396,7 +3396,7 @@ function getParsedComment(text: string, parsingDetails?: ParsingDetails): string }); return text.length <= CONST.MAX_MARKUP_LENGTH - ? parser.replace(textWithMention, {shouldEscapeText: parsingDetails?.shouldEscapeText, filterRules: isGroupPolicyReport ? [] : ['reportMentions']}) + ? parser.replace(textWithMention, {shouldEscapeText: parsingDetails?.shouldEscapeText, disabledRules: isGroupPolicyReport ? [] : ['reportMentions']}) : lodashEscape(text); } From b0b7859f08feb38c69ef1c12651916b1f3dd5a0c Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Mon, 20 May 2024 16:01:01 +0200 Subject: [PATCH 17/18] fix: remove initWithStoredValues setting from AttachmentModal --- src/components/AttachmentModal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index fb6a8e911e87..de98ba79d23c 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -607,7 +607,6 @@ export default withOnyx({ const transactionID = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction?.originalMessage.IOUTransactionID ?? '0' : '0'; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, - initWithStoredValues: false, }, })(memo(AttachmentModal)); From e7e73c8e1c5fea51fc7d5d626afe066b007325c1 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Wed, 22 May 2024 21:32:38 +0200 Subject: [PATCH 18/18] fix: keyboard shortcuts in selection lists --- .../SelectionList/BaseSelectionList.tsx | 13 +++++++++- src/utils/arraysEqual.ts | 25 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/utils/arraysEqual.ts diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 77b296740f2c..3e0ca80b5e41 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -26,6 +26,7 @@ import Log from '@libs/Log'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import arraysEqual from '@src/utils/arraysEqual'; import type {BaseSelectionListProps, ButtonOrCheckBoxRoles, FlattenedSectionsReturn, ListItem, SectionListDataType, SectionWithIndexOffset, SelectionListHandle} from './types'; function BaseSelectionList( @@ -228,11 +229,21 @@ function BaseSelectionList( [flattenedSections.allOptions], ); + const [disabledIndexes, setDisabledIndexes] = useState(flattenedSections.disabledOptionsIndexes); + useEffect(() => { + if (arraysEqual(disabledIndexes, flattenedSections.disabledOptionsIndexes)) { + return; + } + + setDisabledIndexes(flattenedSections.disabledOptionsIndexes); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [flattenedSections.disabledOptionsIndexes]); + // If `initiallyFocusedOptionKey` is not passed, we fall back to `-1`, to avoid showing the highlight on the first member const [focusedIndex, setFocusedIndex] = useArrowKeyFocusManager({ initialFocusedIndex: flattenedSections.allOptions.findIndex((option) => option.keyForList === initiallyFocusedOptionKey), maxIndex: Math.min(flattenedSections.allOptions.length - 1, CONST.MAX_SELECTION_LIST_PAGE_LENGTH * currentPage - 1), - disabledIndexes: flattenedSections.disabledOptionsIndexes, + disabledIndexes, isActive: true, onFocusedIndexChange: (index: number) => { scrollToIndex(index, true); diff --git a/src/utils/arraysEqual.ts b/src/utils/arraysEqual.ts new file mode 100644 index 000000000000..3a8111cc7bb7 --- /dev/null +++ b/src/utils/arraysEqual.ts @@ -0,0 +1,25 @@ +function arraysEqual(a: T[], b: T[]): boolean { + if (a === b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a.length !== b.length) { + return false; + } + + // If you don't care about the order of the elements inside + // the array, you should sort both arrays here. + // Please note that calling sort on an array will modify that array. + // you might want to clone your array first. + + for (let i = 0; i < a.length; ++i) { + if (a[i] !== b[i]) { + return false; + } + } + return true; +} + +export default arraysEqual;