diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 11c2318672d8..8de77ff678a5 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -420,7 +420,7 @@ type OnyxValues = { [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.LEGAL_NAME_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM]: OnyxTypes.Form; - [ONYXKEYS.FORMS.DATE_OF_BIRTH_FORM]: OnyxTypes.Form; + [ONYXKEYS.FORMS.DATE_OF_BIRTH_FORM]: OnyxTypes.DateOfBirthForm; [ONYXKEYS.FORMS.HOME_ADDRESS_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.NEW_ROOM_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.ROOM_SETTINGS_FORM]: OnyxTypes.Form; diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.ts similarity index 56% rename from src/libs/actions/PersonalDetails.js rename to src/libs/actions/PersonalDetails.ts index 351943ca1f29..01f8c2f4916b 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.ts @@ -1,32 +1,38 @@ import Str from 'expensify-common/lib/str'; -import lodashGet from 'lodash/get'; -import Onyx from 'react-native-onyx'; -import _ from 'underscore'; +import Onyx, {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import * as API from '@libs/API'; +import {CustomRNImageManipulatorResult, FileWithUri} from '@libs/cropOrRotateImage/types'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import Navigation from '@libs/Navigation/Navigation'; import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import {DateOfBirthForm, PersonalDetails, PrivatePersonalDetails} from '@src/types/onyx'; +import {Timezone} from '@src/types/onyx/PersonalDetails'; + +type FirstAndLastName = { + firstName: string; + lastName: string; +}; let currentUserEmail = ''; -let currentUserAccountID; +let currentUserAccountID = -1; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { - currentUserEmail = val ? val.email : ''; - currentUserAccountID = val ? val.accountID : -1; + currentUserEmail = val?.email ?? ''; + currentUserAccountID = val?.accountID ?? -1; }, }); -let allPersonalDetails; +let allPersonalDetails: OnyxEntry> = null; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => (allPersonalDetails = val), }); -let privatePersonalDetails; +let privatePersonalDetails: OnyxEntry = null; Onyx.connect({ key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, callback: (val) => (privatePersonalDetails = val), @@ -34,64 +40,60 @@ Onyx.connect({ /** * Returns the displayName for a user - * - * @param {String} login - * @param {Object} [personalDetail] - * @returns {String} */ -function getDisplayName(login, personalDetail) { +function getDisplayName(login: string, personalDetail: Pick | null): string { // If we have a number like +15857527441@expensify.sms then let's remove @expensify.sms and format it // so that the option looks cleaner in our UI. const userLogin = LocalePhoneNumber.formatPhoneNumber(login); - const userDetails = personalDetail || lodashGet(allPersonalDetails, login); + const userDetails = personalDetail ?? allPersonalDetails?.[login]; if (!userDetails) { return userLogin; } - const firstName = userDetails.firstName || ''; - const lastName = userDetails.lastName || ''; + const firstName = userDetails.firstName ?? ''; + const lastName = userDetails.lastName ?? ''; const fullName = `${firstName} ${lastName}`.trim(); + // It's possible for fullName to be empty string, so we must use "||" to fallback to userLogin. return fullName || userLogin; } /** - * @param {String} userAccountIDOrLogin - * @param {String} [defaultDisplayName] display name to use if user details don't exist in Onyx or if + * @param [defaultDisplayName] display name to use if user details don't exist in Onyx or if * found details don't include the user's displayName or login - * @returns {String} */ -function getDisplayNameForTypingIndicator(userAccountIDOrLogin, defaultDisplayName = '') { +function getDisplayNameForTypingIndicator(userAccountIDOrLogin: string, defaultDisplayName = ''): string { // Try to convert to a number, which means we have an accountID const accountID = Number(userAccountIDOrLogin); // If the user is typing on OldDot, userAccountIDOrLogin will be a string (the user's login), // so Number(string) is NaN. Search for personalDetails by login to get the display name. - if (_.isNaN(accountID)) { - const detailsByLogin = _.findWhere(allPersonalDetails, {login: userAccountIDOrLogin}) || {}; - return detailsByLogin.displayName || userAccountIDOrLogin; + if (Number.isNaN(accountID)) { + const detailsByLogin = Object.entries(allPersonalDetails ?? {}).find(([, value]) => value?.login === userAccountIDOrLogin)?.[1]; + + // It's possible for displayName to be empty string, so we must use "||" to fallback to userAccountIDOrLogin. + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + return detailsByLogin?.displayName || userAccountIDOrLogin; } - const detailsByAccountID = lodashGet(allPersonalDetails, accountID, {}); - return detailsByAccountID.displayName || detailsByAccountID.login || defaultDisplayName; + const detailsByAccountID = allPersonalDetails?.[accountID]; + + // It's possible for displayName to be empty string, so we must use "||" to fallback to login or defaultDisplayName. + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + return detailsByAccountID?.displayName || detailsByAccountID?.login || defaultDisplayName; } /** * Gets the first and last name from the user's personal details. * If the login is the same as the displayName, then they don't exist, * so we return empty strings instead. - * @param {Object} personalDetail - * @param {String} personalDetail.login - * @param {String} personalDetail.displayName - * @param {String} personalDetail.firstName - * @param {String} personalDetail.lastName - * - * @returns {Object} */ -function extractFirstAndLastNameFromAvailableDetails({login, displayName, firstName, lastName}) { +function extractFirstAndLastNameFromAvailableDetails({login, displayName, firstName, lastName}: PersonalDetails): FirstAndLastName { + // It's possible for firstName to be empty string, so we must use "||" to consider lastName instead. + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if (firstName || lastName) { - return {firstName: firstName || '', lastName: lastName || ''}; + return {firstName: firstName ?? '', lastName: lastName ?? ''}; } if (login && Str.removeSMSDomain(login) === displayName) { return {firstName: '', lastName: ''}; @@ -112,24 +114,24 @@ function extractFirstAndLastNameFromAvailableDetails({login, displayName, firstN /** * Convert country names obtained from the backend to their respective ISO codes * This is for backward compatibility of stored data before E/App#15507 - * @param {String} countryName - * @returns {String} */ -function getCountryISO(countryName) { - if (_.isEmpty(countryName) || countryName.length === 2) { +function getCountryISO(countryName: string): string { + if (!countryName || countryName.length === 2) { return countryName; } - return _.findKey(CONST.ALL_COUNTRIES, (country) => country === countryName) || ''; + + return Object.entries(CONST.ALL_COUNTRIES).find(([, value]) => value === countryName)?.[0] ?? ''; } -/** - * @param {String} pronouns - */ -function updatePronouns(pronouns) { - API.write( - 'UpdatePronouns', - {pronouns}, - { +function updatePronouns(pronouns: string) { + if (currentUserAccountID) { + type UpdatePronounsParams = { + pronouns: string; + }; + + const parameters: UpdatePronounsParams = {pronouns}; + + API.write('UpdatePronouns', parameters, { optimisticData: [ { onyxMethod: Onyx.METHOD.MERGE, @@ -141,20 +143,22 @@ function updatePronouns(pronouns) { }, }, ], - }, - ); + }); + } + Navigation.goBack(ROUTES.SETTINGS_PROFILE); } -/** - * @param {String} firstName - * @param {String} lastName - */ -function updateDisplayName(firstName, lastName) { - API.write( - 'UpdateDisplayName', - {firstName, lastName}, - { +function updateDisplayName(firstName: string, lastName: string) { + if (currentUserAccountID) { + type UpdateDisplayNameParams = { + firstName: string; + lastName: string; + }; + + const parameters: UpdateDisplayNameParams = {firstName, lastName}; + + API.write('UpdateDisplayName', parameters, { optimisticData: [ { onyxMethod: Onyx.METHOD.MERGE, @@ -163,7 +167,7 @@ function updateDisplayName(firstName, lastName) { [currentUserAccountID]: { firstName, lastName, - displayName: getDisplayName(currentUserEmail, { + displayName: getDisplayName(currentUserEmail ?? '', { firstName, lastName, }), @@ -171,67 +175,73 @@ function updateDisplayName(firstName, lastName) { }, }, ], - }, - ); + }); + } + Navigation.goBack(ROUTES.SETTINGS_PROFILE); } -/** - * @param {String} legalFirstName - * @param {String} legalLastName - */ -function updateLegalName(legalFirstName, legalLastName) { - API.write( - 'UpdateLegalName', - {legalFirstName, legalLastName}, - { - optimisticData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, - value: { - legalFirstName, - legalLastName, - }, +function updateLegalName(legalFirstName: string, legalLastName: string) { + type UpdateLegalNameParams = { + legalFirstName: string; + legalLastName: string; + }; + + const parameters: UpdateLegalNameParams = {legalFirstName, legalLastName}; + + API.write('UpdateLegalName', parameters, { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, + value: { + legalFirstName, + legalLastName, }, - ], - }, - ); + }, + ], + }); + Navigation.goBack(ROUTES.SETTINGS_PERSONAL_DETAILS); } /** - * @param {String} dob - date of birth + * @param dob - date of birth */ -function updateDateOfBirth({dob}) { - API.write( - 'UpdateDateOfBirth', - {dob}, - { - optimisticData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, - value: { - dob, - }, +function updateDateOfBirth({dob}: DateOfBirthForm) { + type UpdateDateOfBirthParams = { + dob?: string; + }; + + const parameters: UpdateDateOfBirthParams = {dob}; + + API.write('UpdateDateOfBirth', parameters, { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, + value: { + dob, }, - ], - }, - ); + }, + ], + }); + Navigation.goBack(ROUTES.SETTINGS_PERSONAL_DETAILS); } -/** - * @param {String} street - * @param {String} street2 - * @param {String} city - * @param {String} state - * @param {String} zip - * @param {String} country - */ -function updateAddress(street, street2, city, state, zip, country) { - const parameters = { +function updateAddress(street: string, street2: string, city: string, state: string, zip: string, country: string) { + type UpdateHomeAddressParams = { + homeAddressStreet: string; + addressStreet2: string; + homeAddressCity: string; + addressState: string; + addressZipCode: string; + addressCountry: string; + addressStateLong?: string; + }; + + const parameters: UpdateHomeAddressParams = { homeAddressStreet: street, addressStreet2: street2, homeAddressCity: city, @@ -245,6 +255,7 @@ function updateAddress(street, street2, city, state, zip, country) { if (country !== CONST.COUNTRY.US) { parameters.addressStateLong = state; } + API.write('UpdateHomeAddress', parameters, { optimisticData: [ { @@ -262,55 +273,61 @@ function updateAddress(street, street2, city, state, zip, country) { }, ], }); + Navigation.goBack(ROUTES.SETTINGS_PERSONAL_DETAILS); } /** * Updates timezone's 'automatic' setting, and updates * selected timezone if set to automatically update. - * - * @param {Object} timezone - * @param {Boolean} timezone.automatic - * @param {String} timezone.selected */ -function updateAutomaticTimezone(timezone) { - API.write( - 'UpdateAutomaticTimezone', - { - timezone: JSON.stringify(timezone), - }, - { - optimisticData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - value: { - [currentUserAccountID]: { - timezone, - }, +function updateAutomaticTimezone(timezone: Timezone) { + if (!currentUserAccountID) { + return; + } + + type UpdateAutomaticTimezoneParams = { + timezone: string; + }; + + const parameters: UpdateAutomaticTimezoneParams = { + timezone: JSON.stringify(timezone), + }; + + API.write('UpdateAutomaticTimezone', parameters, { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: { + [currentUserAccountID]: { + timezone, }, }, - ], - }, - ); + }, + ], + }); } /** * Updates user's 'selected' timezone, then navigates to the * initial Timezone page. - * - * @param {String} selectedTimezone */ -function updateSelectedTimezone(selectedTimezone) { - const timezone = { +function updateSelectedTimezone(selectedTimezone: string) { + const timezone: Timezone = { selected: selectedTimezone, }; - API.write( - 'UpdateSelectedTimezone', - { - timezone: JSON.stringify(timezone), - }, - { + + type UpdateSelectedTimezoneParams = { + timezone: string; + }; + + const parameters: UpdateSelectedTimezoneParams = { + timezone: JSON.stringify(timezone), + }; + + if (currentUserAccountID) { + API.write('UpdateSelectedTimezone', parameters, { optimisticData: [ { onyxMethod: Onyx.METHOD.MERGE, @@ -322,8 +339,9 @@ function updateSelectedTimezone(selectedTimezone) { }, }, ], - }, - ); + }); + } + Navigation.goBack(ROUTES.SETTINGS_TIMEZONE); } @@ -331,7 +349,7 @@ function updateSelectedTimezone(selectedTimezone) { * Fetches additional personal data like legal name, date of birth, address */ function openPersonalDetailsPage() { - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, @@ -341,7 +359,7 @@ function openPersonalDetailsPage() { }, ]; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, @@ -351,7 +369,7 @@ function openPersonalDetailsPage() { }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, @@ -361,17 +379,20 @@ function openPersonalDetailsPage() { }, ]; - API.read('OpenPersonalDetailsPage', {}, {optimisticData, successData, failureData}); + type OpenPersonalDetailsPageParams = Record; + + const parameters: OpenPersonalDetailsPageParams = {}; + + API.read('OpenPersonalDetailsPage', parameters, {optimisticData, successData, failureData}); } /** * Fetches public profile info about a given user. * The API will only return the accountID, displayName, and avatar for the user * but the profile page will use other info (e.g. contact methods and pronouns) if they are already available in Onyx - * @param {Number} accountID */ -function openPublicProfilePage(accountID) { - const optimisticData = [ +function openPublicProfilePage(accountID: number) { + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -382,7 +403,8 @@ function openPublicProfilePage(accountID) { }, }, ]; - const successData = [ + + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -393,7 +415,8 @@ function openPublicProfilePage(accountID) { }, }, ]; - const failureData = [ + + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -404,16 +427,25 @@ function openPublicProfilePage(accountID) { }, }, ]; - API.read('OpenPublicProfilePage', {accountID}, {optimisticData, successData, failureData}); + + type OpenPublicProfilePageParams = { + accountID: number; + }; + + const parameters: OpenPublicProfilePageParams = {accountID}; + + API.read('OpenPublicProfilePage', parameters, {optimisticData, successData, failureData}); } /** * Updates the user's avatar image - * - * @param {File|Object} file */ -function updateAvatar(file) { - const optimisticData = [ +function updateAvatar(file: FileWithUri | CustomRNImageManipulatorResult) { + if (!currentUserAccountID) { + return; + } + + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -434,7 +466,7 @@ function updateAvatar(file) { }, }, ]; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -447,14 +479,14 @@ function updateAvatar(file) { }, }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserAccountID]: { - avatar: allPersonalDetails[currentUserAccountID].avatar, - avatarThumbnail: allPersonalDetails[currentUserAccountID].avatarThumbnail || allPersonalDetails[currentUserAccountID].avatar, + avatar: allPersonalDetails?.[currentUserAccountID]?.avatar, + avatarThumbnail: allPersonalDetails?.[currentUserAccountID]?.avatarThumbnail ?? allPersonalDetails?.[currentUserAccountID]?.avatar, pendingFields: { avatar: null, }, @@ -463,17 +495,27 @@ function updateAvatar(file) { }, ]; - API.write('UpdateUserAvatar', {file}, {optimisticData, successData, failureData}); + type UpdateUserAvatarParams = { + file: FileWithUri | CustomRNImageManipulatorResult; + }; + + const parameters: UpdateUserAvatarParams = {file}; + + API.write('UpdateUserAvatar', parameters, {optimisticData, successData, failureData}); } /** * Replaces the user's avatar image with a default avatar */ function deleteAvatar() { + if (!currentUserAccountID) { + return; + } + // We want to use the old dot avatar here as this affects both platforms. const defaultAvatar = UserUtils.getDefaultAvatarURL(currentUserAccountID); - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -485,26 +527,34 @@ function deleteAvatar() { }, }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserAccountID]: { - avatar: allPersonalDetails[currentUserAccountID].avatar, - fallbackIcon: allPersonalDetails[currentUserAccountID].fallbackIcon, + avatar: allPersonalDetails?.[currentUserAccountID]?.avatar, + fallbackIcon: allPersonalDetails?.[currentUserAccountID]?.fallbackIcon, }, }, }, ]; - API.write('DeleteUserAvatar', {}, {optimisticData, failureData}); + type DeleteUserAvatarParams = Record; + + const parameters: DeleteUserAvatarParams = {}; + + API.write('DeleteUserAvatar', parameters, {optimisticData, failureData}); } /** * Clear error and pending fields for the current user's avatar */ function clearAvatarErrors() { + if (!currentUserAccountID) { + return; + } + Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { [currentUserAccountID]: { errorFields: { @@ -519,28 +569,27 @@ function clearAvatarErrors() { /** * Get private personal details value - * @returns {Object} */ -function getPrivatePersonalDetails() { +function getPrivatePersonalDetails(): OnyxEntry { return privatePersonalDetails; } export { + clearAvatarErrors, + deleteAvatar, + extractFirstAndLastNameFromAvailableDetails, + getCountryISO, getDisplayName, getDisplayNameForTypingIndicator, - updateAvatar, - deleteAvatar, + getPrivatePersonalDetails, openPersonalDetailsPage, openPublicProfilePage, - extractFirstAndLastNameFromAvailableDetails, + updateAddress, + updateAutomaticTimezone, + updateAvatar, + updateDateOfBirth, updateDisplayName, updateLegalName, - updateDateOfBirth, - updateAddress, updatePronouns, - clearAvatarErrors, - updateAutomaticTimezone, updateSelectedTimezone, - getCountryISO, - getPrivatePersonalDetails, }; diff --git a/src/libs/cropOrRotateImage/types.ts b/src/libs/cropOrRotateImage/types.ts index 6abbdab49ea5..09f441bd9324 100644 --- a/src/libs/cropOrRotateImage/types.ts +++ b/src/libs/cropOrRotateImage/types.ts @@ -26,4 +26,4 @@ type CustomRNImageManipulatorResult = RNImageManipulatorResult & {size: number; type CropOrRotateImage = (uri: string, actions: Action[], options: CropOrRotateImageOptions) => Promise; -export type {CropOrRotateImage, CropOptions, Action, FileWithUri, CropOrRotateImageOptions}; +export type {CropOrRotateImage, CropOptions, Action, FileWithUri, CropOrRotateImageOptions, CustomRNImageManipulatorResult}; diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts index cda8c3c1017e..7b7d8d76536a 100644 --- a/src/types/onyx/Form.ts +++ b/src/types/onyx/Form.ts @@ -16,6 +16,11 @@ type AddDebitCardForm = Form & { setupComplete: boolean; }; +type DateOfBirthForm = Form & { + /** Date of birth */ + dob?: string; +}; + export default Form; -export type {AddDebitCardForm}; +export type {AddDebitCardForm, DateOfBirthForm}; diff --git a/src/types/onyx/Login.ts b/src/types/onyx/Login.ts index 60ea5985315e..c770e2f81f90 100644 --- a/src/types/onyx/Login.ts +++ b/src/types/onyx/Login.ts @@ -14,7 +14,7 @@ type Login = { errorFields?: OnyxCommon.ErrorFields; /** Field-specific pending states for offline UI status */ - pendingFields?: OnyxCommon.ErrorFields; + pendingFields?: OnyxCommon.PendingFields; }; export default Login; diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index bafd5e8cbbf0..ef2944d6af82 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -4,7 +4,9 @@ import CONST from '@src/CONST'; type PendingAction = ValueOf; -type ErrorFields = Record | null>; +type PendingFields = Record; + +type ErrorFields = Record; type Errors = Record; @@ -14,4 +16,4 @@ type Icon = { name: string; }; -export type {Icon, PendingAction, ErrorFields, Errors}; +export type {Icon, PendingAction, PendingFields, ErrorFields, Errors}; diff --git a/src/types/onyx/PersonalDetails.ts b/src/types/onyx/PersonalDetails.ts index 0cd264802128..5637d7e5fdcf 100644 --- a/src/types/onyx/PersonalDetails.ts +++ b/src/types/onyx/PersonalDetails.ts @@ -1,3 +1,5 @@ +import * as OnyxCommon from './OnyxCommon'; + type Timezone = { /** Value of selected timezone */ selected?: string; @@ -28,6 +30,11 @@ type PersonalDetails = { /** Avatar URL of the current user from their personal details */ avatar: string; + /** Avatar thumbnail URL of the current user from their personal details */ + avatarThumbnail?: string; + + originalFileName?: string; + /** Flag to set when Avatar uploading */ avatarUploading?: boolean; @@ -43,10 +50,21 @@ type PersonalDetails = { /** Timezone of the current user from their personal details */ timezone?: Timezone; + /** Whether we are loading the data via the API */ + isLoading?: boolean; + + /** Field-specific server side errors keyed by microtime */ + errorFields?: OnyxCommon.ErrorFields<'avatar'>; + + /** Field-specific pending states for offline UI status */ + pendingFields?: OnyxCommon.PendingFields<'avatar' | 'originalFileName'>; + + /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ + fallbackIcon?: string; /** Status of the current user from their personal details */ + status?: string; }; -export type {Timezone}; - export default PersonalDetails; +export type {Timezone}; diff --git a/src/types/onyx/PrivatePersonalDetails.ts b/src/types/onyx/PrivatePersonalDetails.ts index 50ec77212efd..6ef5b75c4a0f 100644 --- a/src/types/onyx/PrivatePersonalDetails.ts +++ b/src/types/onyx/PrivatePersonalDetails.ts @@ -13,6 +13,9 @@ type PrivatePersonalDetails = { /** User's home address */ address?: Address; + + /** Whether we are loading the data via the API */ + isLoading?: boolean; }; export default PrivatePersonalDetails; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index de5f2eec9f9d..e52389a72b46 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -56,7 +56,7 @@ type Transaction = { created: string; currency: string; errors?: OnyxCommon.Errors; - errorFields?: OnyxCommon.ErrorFields; + errorFields?: OnyxCommon.ErrorFields<'route'>; // The name of the file used for a receipt (formerly receiptFilename) filename?: string; merchant: string; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 93a19b39aad3..f02d3d2f548f 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -8,7 +8,7 @@ import Credentials from './Credentials'; import Currency from './Currency'; import CustomStatusDraft from './CustomStatusDraft'; import Download from './Download'; -import Form, {AddDebitCardForm} from './Form'; +import Form, {AddDebitCardForm, DateOfBirthForm} from './Form'; import FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import Fund from './Fund'; import IOU from './IOU'; @@ -51,58 +51,59 @@ import WalletTransfer from './WalletTransfer'; export type { Account, - Request, + AccountData, + AddDebitCardForm, + BankAccount, + Beta, + BlockedFromConcierge, + Card, Credentials, + Currency, + CustomStatusDraft, + DateOfBirthForm, + Download, + Form, + FrequentlyUsedEmoji, + Fund, IOU, + Login, + MapboxAccessToken, Modal, Network, - CustomStatusDraft, + OnyxUpdateEvent, + OnyxUpdatesFromServer, + PersonalBankAccount, PersonalDetails, - PrivatePersonalDetails, - Task, - Currency, - ScreenShareRequest, - User, - Login, - Session, - Beta, - BlockedFromConcierge, PlaidData, - UserWallet, - WalletOnfido, - WalletAdditionalDetails, - WalletTerms, - BankAccount, - Card, - Fund, - WalletStatement, - PersonalBankAccount, - ReimbursementAccount, - ReimbursementAccountDraft, - FrequentlyUsedEmoji, - WalletTransfer, - MapboxAccessToken, - Download, - PolicyMember, Policy, PolicyCategory, + PolicyMember, + PolicyMembers, + PolicyTag, + PolicyTags, + PrivatePersonalDetails, + RecentlyUsedCategories, + RecentlyUsedTags, + RecentWaypoint, + ReimbursementAccount, + ReimbursementAccountDraft, Report, - ReportMetadata, ReportAction, + ReportActionReactions, ReportActions, ReportActionsDrafts, - ReportActionReactions, + ReportMetadata, + Request, + ScreenShareRequest, SecurityGroup, + Session, + Task, Transaction, - Form, - AddDebitCardForm, - OnyxUpdatesFromServer, - RecentWaypoint, - OnyxUpdateEvent, - RecentlyUsedCategories, - RecentlyUsedTags, - PolicyTag, - PolicyTags, - PolicyMembers, - AccountData, + User, + UserWallet, + WalletAdditionalDetails, + WalletOnfido, + WalletStatement, + WalletTerms, + WalletTransfer, };