Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/ConnectToNetSuiteFlow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import {isAuthenticationError} from '@libs/actions/connections';
import {getAdminPoliciesConnectedToNetSuite} from '@libs/actions/Policy/Policy';
import Navigation from '@libs/Navigation/Navigation';
import {useAccountingContext} from '@pages/workspace/accounting/AccountingContext';
import {getInitialSubPageForNetsuiteTokenInput} from '@pages/workspace/accounting/netsuite/utils';
import type {AnchorPosition} from '@styles/index';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import {getInitialSubPageForNetsuiteTokenInput} from '@pages/workspace/accounting/netsuite/utils';
import type {ConnectToNetSuiteFlowProps} from './types';

function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) {
Expand Down
201 changes: 0 additions & 201 deletions src/components/SelectionListWithSections/Search/ActionCell.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import {View} from 'react-native';
import Badge from '@components/Badge';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import type {SearchTransactionAction} from '@src/types/onyx/SearchResults';
import actionTranslationsMap from './actionTranslationsMap';

type BadgeActionCellProps = {
action: SearchTransactionAction;
isLargeScreenWidth: boolean;
isSelected: boolean;
extraSmall: boolean;
shouldDisablePointerEvents?: boolean;
};

function BadgeActionCell({action, isLargeScreenWidth, isSelected, extraSmall, shouldDisablePointerEvents}: BadgeActionCellProps) {
const {translate} = useLocalize();
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Checkmark', 'Checkbox']);
const text = translate(actionTranslationsMap[action]);

return (
<View
style={[StyleUtils.getHeight(variables.h20), styles.justifyContentCenter, shouldDisablePointerEvents && styles.pointerEventsNone]}
accessible={!shouldDisablePointerEvents}
accessibilityState={{disabled: shouldDisablePointerEvents}}
>
<Badge
text={text}
icon={action === CONST.SEARCH.ACTION_TYPES.DONE ? expensifyIcons.Checkbox : expensifyIcons.Checkmark}
badgeStyles={[
styles.ml0,
styles.ph2,
styles.gap1,
isLargeScreenWidth ? styles.alignSelfCenter : styles.alignSelfEnd,
StyleUtils.getHeight(variables.h20),
StyleUtils.getMinimumHeight(variables.h20),
isSelected ? StyleUtils.getBorderColorStyle(theme.buttonHoveredBG) : StyleUtils.getBorderColorStyle(theme.border),
]}
textStyles={StyleUtils.getFontSizeStyle(extraSmall ? variables.fontSizeExtraSmall : variables.fontSizeSmall)}
iconStyles={styles.mr0}
success
shouldUseXXSmallIcon={extraSmall}
/>
</View>
);
}

export type {BadgeActionCellProps};
export default BadgeActionCell;
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import type {ValueOf} from 'type-fest';
import {useDelegateNoAccessActions, useDelegateNoAccessState} from '@components/DelegateNoAccessModalProvider';
import type {PaymentMethod} from '@components/KYCWall/types';
import {SearchScopeProvider} from '@components/Search/SearchScopeProvider';
import SettlementButton from '@components/SettlementButton';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import usePolicy from '@hooks/usePolicy';
import useReportWithTransactionsAndViolations from '@hooks/useReportWithTransactionsAndViolations';
import useThemeStyles from '@hooks/useThemeStyles';
import {canIOUBePaid} from '@libs/actions/IOU';
import {getPayMoneyOnSearchInvoiceParams, payMoneyRequestOnSearch} from '@libs/actions/Search';
import {convertToDisplayString} from '@libs/CurrencyUtils';
import {isInvoiceReport} from '@libs/ReportUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';

type PayActionCellProps = {
isLoading: boolean;
policyID: string;
reportID: string;
hash?: number;
amount?: number;
extraSmall: boolean;
shouldDisablePointerEvents?: boolean;
};

function PayActionCell({isLoading, policyID, reportID, hash, amount, extraSmall, shouldDisablePointerEvents}: PayActionCellProps) {
const styles = useThemeStyles();
const {isOffline} = useNetwork();
const {isDelegateAccessRestricted} = useDelegateNoAccessState();
const {showDelegateNoAccessModal} = useDelegateNoAccessActions();
const [iouReport, transactions] = useReportWithTransactionsAndViolations(reportID);
const policy = usePolicy(policyID);
const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`);
const canBePaid = canIOUBePaid(iouReport, chatReport, policy, bankAccountList, transactions, false);
const shouldOnlyShowElsewhere = !canBePaid && canIOUBePaid(iouReport, chatReport, policy, bankAccountList, transactions, true);

const {currency} = iouReport ?? {};

const confirmPayment = (type: ValueOf<typeof CONST.IOU.PAYMENT_TYPE> | undefined, payAsBusiness?: boolean, methodID?: number, paymentMethod?: PaymentMethod | undefined) => {
if (!type || !reportID || !hash || !amount) {
return;
}

if (isDelegateAccessRestricted) {
showDelegateNoAccessModal();
return;
}

const invoiceParams = getPayMoneyOnSearchInvoiceParams(policyID, payAsBusiness, methodID, paymentMethod);
payMoneyRequestOnSearch(hash, [{amount, paymentType: type, reportID, ...(isInvoiceReport(iouReport) ? invoiceParams : {})}]);
};

return (
<SearchScopeProvider isOnSearch={false}>
<SettlementButton
shouldUseShortForm
buttonSize={extraSmall ? CONST.DROPDOWN_BUTTON_SIZE.EXTRA_SMALL : CONST.DROPDOWN_BUTTON_SIZE.SMALL}
currency={currency}
formattedAmount={convertToDisplayString(Math.abs(iouReport?.total ?? 0), currency)}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
policyID={policyID || iouReport?.policyID}
iouReport={iouReport}
chatReportID={iouReport?.chatReportID}
enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS}
onPress={(type, payAsBusiness, methodID, paymentMethod) => confirmPayment(type as ValueOf<typeof CONST.IOU.PAYMENT_TYPE>, payAsBusiness, methodID, paymentMethod)}
style={[styles.w100, shouldDisablePointerEvents && styles.pointerEventsNone]}
wrapperStyle={[styles.w100]}
Copy link
Contributor

Choose a reason for hiding this comment

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

❌ CONSISTENCY-5 (docs)

This eslint-disable-next-line suppresses @typescript-eslint/prefer-nullish-coalescing without an accompanying comment explaining why the logical OR (||) is preferred over nullish coalescing (??) here.

Add a comment explaining the reason, for example:

// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- We intentionally use || because empty string policyID should fall through to iouReport?.policyID
policyID={policyID || iouReport?.policyID}

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a valid comment (unless we specifically want to use iouReport?.policyID if policyID is 0 (CONST.DEFAULT_NUMBER_ID)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TBH - this part of code was just moved - earlier it was like this in src/components/SelectionListWithSections/Search/ActionCell.tsx#165.

IMO adding a comment like a bit suggests seems bit redundant, as the code is self explanatory here. WDYT ?

Copy link
Contributor

Choose a reason for hiding this comment

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

TBH - this part of code was just moved - earlier it was like this in

But why was it implemented like that initially? Is there a reason we must use (||) instead of (??)?
This is the only instance throughout the app where it's used for policyID

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, fair point I think it was introduced by this PR and I think there was no @typescript-eslint/prefer-nullish-coalescing rule at that point.

@getusha is there a reason you user || here ?

Copy link
Contributor

Choose a reason for hiding this comment

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

That seems like an oversight to me

Copy link
Contributor

Choose a reason for hiding this comment

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

@getusha is there a reason you user || here ?

I'm not really sure, but I think policyID can somehow be an empty string.

shouldShowPersonalBankAccountOption={!policyID && !iouReport?.policyID}
isDisabled={isOffline || shouldDisablePointerEvents}
shouldStayNormalOnDisable={shouldDisablePointerEvents}
isLoading={isLoading}
onlyShowPayElsewhere={shouldOnlyShowElsewhere}
sentryLabel={CONST.SENTRY_LABEL.SEARCH.ACTION_CELL_PAY}
/>
</SearchScopeProvider>
);
}

export type {PayActionCellProps};
export default PayActionCell;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import type {SearchTransactionAction} from '@src/types/onyx/SearchResults';

const actionTranslationsMap: Record<SearchTransactionAction, TranslationPaths> = {
[CONST.SEARCH.ACTION_TYPES.VIEW]: 'common.view',
[CONST.SEARCH.ACTION_TYPES.SUBMIT]: 'common.submit',
[CONST.SEARCH.ACTION_TYPES.APPROVE]: 'iou.approve',
[CONST.SEARCH.ACTION_TYPES.PAY]: 'iou.pay',
[CONST.SEARCH.ACTION_TYPES.EXPORT_TO_ACCOUNTING]: 'common.export',
[CONST.SEARCH.ACTION_TYPES.DONE]: 'common.done',
[CONST.SEARCH.ACTION_TYPES.PAID]: 'iou.settledExpensify',
};

export default actionTranslationsMap;
Loading
Loading