Skip to content

Commit

Permalink
Merge branch 'Expensify:main' into prefer-shouldUseNarrowLayout-inste…
Browse files Browse the repository at this point in the history
…ad-of-isSmallScreenWidth-eslint-rule
  • Loading branch information
rayane-djouah authored Oct 21, 2024
2 parents a860619 + 36a8b13 commit f6f66ab
Show file tree
Hide file tree
Showing 67 changed files with 2,163 additions and 1,051 deletions.
263 changes: 263 additions & 0 deletions assets/images/companyCards/pending-bank.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions assets/images/gallery-not-found.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 43 additions & 3 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,19 @@ const CONST = {
PERSONAL: 'PERSONAL',
},
},
NON_USD_BANK_ACCOUNT: {
STEP: {
COUNTRY: 'CountryStep',
BANK_INFO: 'BankInfoStep',
BUSINESS_INFO: 'BusinessInfoStep',
BENEFICIAL_OWNER_INFO: 'BeneficialOwnerInfoStep',
SIGNER_INFO: 'SignerInfoStep',
AGREEMENTS: 'AgreementsStep',
FINISH: 'FinishStep',
},
STEP_NAMES: ['1', '2', '3', '4', '5', '6'],
STEP_HEADER_HEIGHT: 40,
},
INCORPORATION_TYPES: {
LLC: 'LLC',
CORPORATION: 'Corp',
Expand Down Expand Up @@ -1130,9 +1143,6 @@ const CONST = {
SEARCH_OPTION_LIST_DEBOUNCE_TIME: 300,
RESIZE_DEBOUNCE_TIME: 100,
UNREAD_UPDATE_DEBOUNCE_TIME: 300,
SEARCH_CONVERT_SEARCH_VALUES: 'search_convert_search_values',
SEARCH_MAKE_TREE: 'search_make_tree',
SEARCH_BUILD_TREE: 'search_build_tree',
SEARCH_FILTER_OPTIONS: 'search_filter_options',
USE_DEBOUNCED_STATE_DELAY: 300,
},
Expand Down Expand Up @@ -2529,6 +2539,13 @@ const CONST = {
VISA: 'vcf',
AMEX: 'gl1025',
STRIPE: 'stripe',
CITIBANK: 'oauth.citibank.com',
CAPITAL_ONE: 'oauth.capitalone.com',
BANK_OF_AMERICA: 'oauth.bankofamerica.com',
CHASE: 'oauth.chase.com',
BREX: 'oauth.brex.com',
WELLS_FARGO: 'oauth.wellsfargo.com',
AMEX_DIRECT: 'oauth.americanexpressfdx.com',
},
STEP_NAMES: ['1', '2', '3', '4'],
STEP: {
Expand Down Expand Up @@ -2616,6 +2633,14 @@ const CONST = {
WELLS_FARGO: 'Wells Fargo',
OTHER: 'Other',
},
BANK_CONNECTIONS: {
WELLS_FARGO: 'wellsfargo',
CHASE: 'chase',
BREX: 'brex',
CAPITAL_ONE: 'capitalone',
CITI_BANK: 'citibank',
AMEX: 'americanexpressfdx',
},
AMEX_CUSTOM_FEED: {
CORPORATE: 'American Express Corporate Cards',
BUSINESS: 'American Express Business Cards',
Expand Down Expand Up @@ -5905,6 +5930,21 @@ const CONST = {
// The timeout duration (1 minute) (in milliseconds) before the window reloads due to an error.
ERROR_WINDOW_RELOAD_TIMEOUT: 60000,

INDICATOR_STATUS: {
HAS_USER_WALLET_ERRORS: 'hasUserWalletErrors',
HAS_PAYMENT_METHOD_ERROR: 'hasPaymentMethodError',
HAS_POLICY_ERRORS: 'hasPolicyError',
HAS_CUSTOM_UNITS_ERROR: 'hasCustomUnitsError',
HAS_EMPLOYEE_LIST_ERROR: 'hasEmployeeListError',
HAS_SYNC_ERRORS: 'hasSyncError',
HAS_SUBSCRIPTION_ERRORS: 'hasSubscriptionError',
HAS_REIMBURSEMENT_ACCOUNT_ERRORS: 'hasReimbursementAccountErrors',
HAS_LOGIN_LIST_ERROR: 'hasLoginListError',
HAS_WALLET_TERMS_ERRORS: 'hasWalletTermsErrors',
HAS_LOGIN_LIST_INFO: 'hasLoginListInfo',
HAS_SUBSCRIPTION_INFO: 'hasSubscriptionInfo',
},

DEBUG: {
DETAILS: 'details',
JSON: 'json',
Expand Down
1 change: 1 addition & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const PUBLIC_SCREENS_ROUTES = {
ROOT: '',
TRANSITION_BETWEEN_APPS: 'transition',
CONNECTION_COMPLETE: 'connection-complete',
BANK_CONNECTION_COMPLETE: 'bank-connection-complete',
VALIDATE_LOGIN: 'v/:accountID/:validateCode',
UNLINK_LOGIN: 'u/:accountID/:validateCode',
APPLE_SIGN_IN: 'sign-in-with-apple',
Expand Down
2 changes: 1 addition & 1 deletion src/components/AttachmentOfflineIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function AttachmentOfflineIndicator({isPreview = false}: AttachmentOfflineIndica
return (
<View style={[styles.flexColumn, styles.alignItemsCenter, styles.justifyContentCenter, styles.pAbsolute, styles.h100, styles.w100, isPreview && styles.hoveredComponentBG]}>
<Icon
fill={theme.border}
fill={theme.icon}
src={Expensicons.OfflineCloud}
width={variables.iconSizeSuperLarge}
height={variables.iconSizeSuperLarge}
Expand Down
13 changes: 11 additions & 2 deletions src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {memo} from 'react';
import React, {memo, useState} from 'react';
import {useOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import type {CustomRendererProps, TBlock} from 'react-native-render-html';
Expand All @@ -8,6 +8,7 @@ import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
import ThumbnailImage from '@components/ThumbnailImage';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as FileUtils from '@libs/fileDownload/FileUtils';
import Navigation from '@libs/Navigation/Navigation';
Expand Down Expand Up @@ -63,7 +64,10 @@ function ImageRenderer({tnode}: ImageRendererProps) {
const imagePreviewModalDisabled = htmlAttribs['data-expensify-preview-modal-disabled'] === 'true';

const fileType = FileUtils.getFileType(attachmentSourceAttribute);
const fallbackIcon = fileType === CONST.ATTACHMENT_FILE_TYPE.FILE ? Expensicons.Document : Expensicons.Gallery;
const fallbackIcon = fileType === CONST.ATTACHMENT_FILE_TYPE.FILE ? Expensicons.Document : Expensicons.GalleryNotFound;
const [hasLoadFailed, setHasLoadFailed] = useState(true);
const theme = useTheme();

const thumbnailImageComponent = (
<ThumbnailImage
previewSourceURL={previewSource}
Expand All @@ -73,6 +77,10 @@ function ImageRenderer({tnode}: ImageRendererProps) {
imageWidth={imageWidth}
imageHeight={imageHeight}
altText={alt}
onLoadFailure={() => setHasLoadFailed(true)}
onMeasure={() => setHasLoadFailed(false)}
fallbackIconBackground={theme.highlightBG}
fallbackIconColor={theme.border}
/>
);

Expand Down Expand Up @@ -102,6 +110,7 @@ function ImageRenderer({tnode}: ImageRendererProps) {
shouldUseHapticsOnLongPress
accessibilityRole={CONST.ROLE.BUTTON}
accessibilityLabel={translate('accessibilityHints.viewAttachment')}
disabled={hasLoadFailed}
>
{thumbnailImageComponent}
</PressableWithoutFocus>
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon/Expensicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import FlagLevelTwo from '@assets/images/flag_level_02.svg';
import FlagLevelThree from '@assets/images/flag_level_03.svg';
import Folder from '@assets/images/folder.svg';
import Fullscreen from '@assets/images/fullscreen.svg';
import GalleryNotFound from '@assets/images/gallery-not-found.svg';
import Gallery from '@assets/images/gallery.svg';
import Gear from '@assets/images/gear.svg';
import Globe from '@assets/images/globe.svg';
Expand Down Expand Up @@ -404,4 +405,5 @@ export {
Bookmark,
Star,
QBDSquare,
GalleryNotFound,
};
2 changes: 2 additions & 0 deletions src/components/Icon/Illustrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import WellsFargoCompanyCardDetail from '@assets/images/companyCards/card-wellsf
import OtherCompanyCardDetail from '@assets/images/companyCards/card=-generic.svg';
import CompanyCardsEmptyState from '@assets/images/companyCards/emptystate__card-pos.svg';
import MasterCardCompanyCards from '@assets/images/companyCards/mastercard.svg';
import PendingBank from '@assets/images/companyCards/pending-bank.svg';
import CompanyCardsPendingState from '@assets/images/companyCards/pendingstate_laptop-with-hourglass-and-cards.svg';
import VisaCompanyCards from '@assets/images/companyCards/visa.svg';
import EmptyCardState from '@assets/images/emptystate__expensifycard.svg';
Expand Down Expand Up @@ -207,6 +208,7 @@ export {
Approval,
WalletAlt,
Workflows,
PendingBank,
ThreeLeggedLaptopWoman,
House,
Alert,
Expand Down
102 changes: 5 additions & 97 deletions src/components/Indicator.tsx
Original file line number Diff line number Diff line change
@@ -1,109 +1,17 @@
import React from 'react';
import {StyleSheet, View} from 'react-native';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import {useOnyx, withOnyx} from 'react-native-onyx';
import useTheme from '@hooks/useTheme';
import useIndicatorStatus from '@hooks/useIndicatorStatus';
import useThemeStyles from '@hooks/useThemeStyles';
import {isConnectionInProgress} from '@libs/actions/connections';
import * as PolicyUtils from '@libs/PolicyUtils';
import * as SubscriptionUtils from '@libs/SubscriptionUtils';
import * as UserUtils from '@libs/UserUtils';
import * as PaymentMethods from '@userActions/PaymentMethods';
import ONYXKEYS from '@src/ONYXKEYS';
import type {BankAccountList, FundList, LoginList, Policy, ReimbursementAccount, UserWallet, WalletTerms} from '@src/types/onyx';

type CheckingMethod = () => boolean;

type IndicatorOnyxProps = {
/** All the user's policies (from Onyx via withFullPolicy) */
policies: OnyxCollection<Policy>;

/** List of bank accounts */
bankAccountList: OnyxEntry<BankAccountList>;

/** List of user cards */
fundList: OnyxEntry<FundList>;

/** The user's wallet (coming from Onyx) */
userWallet: OnyxEntry<UserWallet>;

/** Bank account attached to free plan */
reimbursementAccount: OnyxEntry<ReimbursementAccount>;

/** Information about the user accepting the terms for payments */
walletTerms: OnyxEntry<WalletTerms>;

/** Login list for the user that is signed in */
loginList: OnyxEntry<LoginList>;
};

type IndicatorProps = IndicatorOnyxProps;

function Indicator({reimbursementAccount, policies, bankAccountList, fundList, userWallet, walletTerms, loginList}: IndicatorOnyxProps) {
const theme = useTheme();
function Indicator() {
const styles = useThemeStyles();
const [allConnectionSyncProgresses] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}`);

// If a policy was just deleted from Onyx, then Onyx will pass a null value to the props, and
// those should be cleaned out before doing any error checking
const cleanPolicies = Object.fromEntries(Object.entries(policies ?? {}).filter(([, policy]) => policy?.id));

// All of the error & info-checking methods are put into an array. This is so that using _.some() will return
// early as soon as the first error / info condition is returned. This makes the checks very efficient since
// we only care if a single error / info condition exists anywhere.
const errorCheckingMethods: CheckingMethod[] = [
() => Object.keys(userWallet?.errors ?? {}).length > 0,
() => PaymentMethods.hasPaymentMethodError(bankAccountList, fundList),
() => Object.values(cleanPolicies).some(PolicyUtils.hasPolicyError),
() => Object.values(cleanPolicies).some(PolicyUtils.hasCustomUnitsError),
() => Object.values(cleanPolicies).some(PolicyUtils.hasEmployeeListError),
() =>
Object.values(cleanPolicies).some((cleanPolicy) =>
PolicyUtils.hasSyncError(
cleanPolicy,
isConnectionInProgress(allConnectionSyncProgresses?.[`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${cleanPolicy?.id}`], cleanPolicy),
),
),
() => SubscriptionUtils.hasSubscriptionRedDotError(),
() => Object.keys(reimbursementAccount?.errors ?? {}).length > 0,
() => !!loginList && UserUtils.hasLoginListError(loginList),

// Wallet term errors that are not caused by an IOU (we show the red brick indicator for those in the LHN instead)
() => Object.keys(walletTerms?.errors ?? {}).length > 0 && !walletTerms?.chatReportID,
];
const infoCheckingMethods: CheckingMethod[] = [() => !!loginList && UserUtils.hasLoginListInfo(loginList), () => SubscriptionUtils.hasSubscriptionGreenDotInfo()];
const shouldShowErrorIndicator = errorCheckingMethods.some((errorCheckingMethod) => errorCheckingMethod());
const shouldShowInfoIndicator = !shouldShowErrorIndicator && infoCheckingMethods.some((infoCheckingMethod) => infoCheckingMethod());
const {indicatorColor, status} = useIndicatorStatus();

const indicatorColor = shouldShowErrorIndicator ? theme.danger : theme.success;
const indicatorStyles = [styles.alignItemsCenter, styles.justifyContentCenter, styles.statusIndicator(indicatorColor)];

return (shouldShowErrorIndicator || shouldShowInfoIndicator) && <View style={StyleSheet.flatten(indicatorStyles)} />;
return !!status && <View style={StyleSheet.flatten(indicatorStyles)} />;
}

Indicator.displayName = 'Indicator';

export default withOnyx<IndicatorProps, IndicatorOnyxProps>({
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
bankAccountList: {
key: ONYXKEYS.BANK_ACCOUNT_LIST,
},
// @ts-expect-error: ONYXKEYS.REIMBURSEMENT_ACCOUNT is conflicting with ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM
reimbursementAccount: {
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
},
fundList: {
key: ONYXKEYS.FUND_LIST,
},
userWallet: {
key: ONYXKEYS.USER_WALLET,
},
walletTerms: {
key: ONYXKEYS.WALLET_TERMS,
},
loginList: {
key: ONYXKEYS.LOGIN_LIST,
},
})(Indicator);
export default Indicator;
Loading

0 comments on commit f6f66ab

Please sign in to comment.