Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TS migration] Migrate IOURequestStepTaxRatePage and IOURequestStepTaxAmountPage to TypeScript #39059

3 changes: 1 addition & 2 deletions src/components/TaxPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import ONYXKEYS from '@src/ONYXKEYS';
import type {Policy} from '@src/types/onyx';
import SelectionList from './SelectionList';
import RadioListItem from './SelectionList/RadioListItem';
import type {ListItem} from './SelectionList/types';

type TaxPickerOnyxProps = {
/** The policy which the user has access to and which the report is tied to */
Expand All @@ -33,7 +32,7 @@ type TaxPickerProps = TaxPickerOnyxProps & {
insets?: EdgeInsets;

/** Callback to fire when a tax is pressed */
onSubmit: (tax: ListItem) => void;
onSubmit: (tax: OptionsListUtils.TaxRatesOption) => void;
};

function TaxPicker({selectedTaxRate = '', policy, insets, onSubmit}: TaxPickerProps) {
Expand Down
4 changes: 2 additions & 2 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ type MoneyRequestNavigatorParamList = {
backTo: Routes;
};
[SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: {
iouType: string;
iouType: ValueOf<typeof CONST.IOU.TYPE>;
transactionID: string;
reportID: string;
backTo: Routes;
Expand All @@ -395,7 +395,7 @@ type MoneyRequestNavigatorParamList = {
backTo: Routes;
};
[SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: {
iouType: string;
iouType: ValueOf<typeof CONST.IOU.TYPE>;
transactionID: string;
reportID: string;
backTo: Routes;
Expand Down
22 changes: 19 additions & 3 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,22 @@ type CategorySection = CategorySectionBase & {
data: Option[];
};

type TaxRatesOption = {
text?: string;
code?: string;
searchText?: string;
tooltipText?: string;
isDisabled?: boolean;
keyForList?: string;
data: Partial<TaxRate>;
};

type TaxSection = {
title: string | undefined;
shouldShow: boolean;
data: TaxRatesOption[];
};

type CategoryTreeSection = CategorySectionBase & {
data: OptionTree[];
};
Expand Down Expand Up @@ -1240,7 +1256,7 @@ function sortTaxRates(taxRates: TaxRates): TaxRate[] {
/**
* Builds the options for taxRates
*/
function getTaxRatesOptions(taxRates: Array<Partial<TaxRate>>): Option[] {
function getTaxRatesOptions(taxRates: Array<Partial<TaxRate>>): TaxRatesOption[] {
return taxRates.map((taxRate) => ({
text: taxRate.modifiedName,
keyForList: taxRate.modifiedName,
Expand All @@ -1254,7 +1270,7 @@ function getTaxRatesOptions(taxRates: Array<Partial<TaxRate>>): Option[] {
/**
* Builds the section list for tax rates
*/
function getTaxRatesSection(taxRates: TaxRatesWithDefault | undefined, selectedOptions: Category[], searchInputValue: string): CategorySection[] {
function getTaxRatesSection(taxRates: TaxRatesWithDefault | undefined, selectedOptions: Category[], searchInputValue: string): TaxSection[] {
const policyRatesSections = [];

const taxes = transformedTaxRates(taxRates);
Expand Down Expand Up @@ -2125,4 +2141,4 @@ export {
getTaxRatesSection,
};

export type {MemberForList, CategorySection, GetOptions, OptionList, SearchOption, PayeePersonalDetails, Category};
export type {MemberForList, CategorySection, GetOptions, OptionList, SearchOption, PayeePersonalDetails, Category, TaxRatesOption};
5 changes: 3 additions & 2 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
import * as Localize from '@libs/Localize';
import Navigation from '@libs/Navigation/Navigation';
import * as NextStepUtils from '@libs/NextStepUtils';
import type {TaxRatesOption} from '@libs/OptionsListUtils';
import Permissions from '@libs/Permissions';
import * as PhoneNumber from '@libs/PhoneNumber';
import * as PolicyUtils from '@libs/PolicyUtils';
Expand All @@ -54,7 +55,7 @@ import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
import type ReportAction from '@src/types/onyx/ReportAction';
import type {OnyxData} from '@src/types/onyx/Request';
import type {Comment, Receipt, ReceiptSource, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
import type {Comment, Receipt, ReceiptSource, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
import type {EmptyObject} from '@src/types/utils/EmptyObject';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import * as CachedPDFPaths from './CachedPDFPaths';
Expand Down Expand Up @@ -5112,7 +5113,7 @@ function setMoneyRequestCurrency(currency: string) {
Onyx.merge(ONYXKEYS.IOU, {currency});
}

function setMoneyRequestTaxRate(transactionID: string, taxRate: TaxRate) {
function setMoneyRequestTaxRate(transactionID: string, taxRate: TaxRatesOption) {
Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {taxRate});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,84 +1,69 @@
import {useFocusEffect} from '@react-navigation/native';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useRef} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import taxPropTypes from '@components/taxPropTypes';
import transactionPropTypes from '@components/transactionPropTypes';
import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';
import useLocalize from '@hooks/useLocalize';
import compose from '@libs/compose';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as TransactionUtils from '@libs/TransactionUtils';
import type {CurrentMoney} from '@pages/iou/steps/MoneyRequestAmountForm';
import MoneyRequestAmountForm from '@pages/iou/steps/MoneyRequestAmountForm';
import reportPropTypes from '@pages/reportPropTypes';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes';
import type SCREENS from '@src/SCREENS';
import type {Policy, Transaction} from '@src/types/onyx';
import StepScreenWrapper from './StepScreenWrapper';
import withFullTransactionOrNotFound from './withFullTransactionOrNotFound';
import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound';
import withWritableReportOrNotFound from './withWritableReportOrNotFound';

const propTypes = {
/** Navigation route context info provided by react navigation */
route: IOURequestStepRoutePropTypes.isRequired,

/* Onyx Props */
/** The report that the transaction belongs to */
report: reportPropTypes,

/** The transaction object being modified in Onyx */
transaction: transactionPropTypes,

/* Onyx Props */
/** The policy of the report */
policy: PropTypes.shape({
/** Collection of tax rates attached to a policy */
taxRates: taxPropTypes,
}),
type IOURequestStepTaxAmountPageOnyxProps = {
policy: OnyxEntry<Policy>;
};

const defaultProps = {
report: {},
policy: {},
transaction: {},
};
type IOURequestStepTaxAmountPageProps = IOURequestStepTaxAmountPageOnyxProps &
WithWritableReportOrNotFoundProps<typeof SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT> & {
transaction: OnyxEntry<Transaction>;
};

const getTaxAmount = (transaction, defaultTaxValue) => {
const percentage = (transaction.taxRate ? transaction.taxRate.data.value : defaultTaxValue) || '';
return CurrencyUtils.convertToBackendAmount(Number.parseFloat(TransactionUtils.calculateTaxAmount(percentage, transaction.amount)));
};
function getTaxAmount(transaction: OnyxEntry<Transaction>, defaultTaxValue: string | undefined): number | undefined {
if (!transaction?.amount) {
return;
}
Comment on lines +33 to +35
Copy link
Contributor

Choose a reason for hiding this comment

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

This incomplete condition lead to this bug here #41434

const percentage = (transaction?.taxRate ? transaction?.taxRate?.data?.value : defaultTaxValue) ?? '';
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const percentage = (transaction?.taxRate ? transaction?.taxRate?.data?.value : defaultTaxValue) ?? '';
const percentage = (transaction?.taxRate ? transaction?.taxRate?.data?.value : defaultTaxValue) ?? '';

return CurrencyUtils.convertToBackendAmount(TransactionUtils.calculateTaxAmount(percentage, transaction?.amount));
}

function IOURequestStepTaxAmountPage({
route: {
params: {iouType, reportID, transactionID, backTo},
},
transaction,
transaction: {currency},
report,
policy,
}) {
}: IOURequestStepTaxAmountPageProps) {
const {translate} = useLocalize();
const textInput = useRef(null);
const textInput = useRef<BaseTextInputRef | null>();
const isEditing = Navigation.getActiveRoute().includes('taxAmount');

const focusTimeoutRef = useRef(null);
const focusTimeoutRef = useRef<NodeJS.Timeout>();

const isSaveButtonPressed = useRef(false);
const originalCurrency = useRef(null);
const taxRates = lodashGet(policy, 'taxRates', {});
const originalCurrency = useRef<string>();
const taxRates = policy?.taxRates;

useEffect(() => {
if (transaction.originalCurrency) {
if (transaction?.originalCurrency) {
originalCurrency.current = transaction.originalCurrency;
} else {
originalCurrency.current = currency;
IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currency);
} else if (transaction?.currency) {
Copy link
Contributor

Choose a reason for hiding this comment

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

make sure this change won't create regressions

originalCurrency.current = transaction.currency;
IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, transaction?.currency);
}
return () => {
if (isSaveButtonPressed.current) {
if (isSaveButtonPressed.current || !originalCurrency.current) {
Copy link
Contributor

Choose a reason for hiding this comment

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

same

return;
}
IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, originalCurrency.current, true);
Expand All @@ -88,7 +73,7 @@ function IOURequestStepTaxAmountPage({

useFocusEffect(
useCallback(() => {
focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION);
focusTimeoutRef.current = setTimeout(() => textInput.current?.focus(), CONST.ANIMATED_TRANSITION);
return () => {
if (!focusTimeoutRef.current) {
return;
Expand All @@ -111,12 +96,13 @@ function IOURequestStepTaxAmountPage({
);
};

const updateTaxAmount = (currentAmount) => {
const updateTaxAmount = (currentAmount: CurrentMoney) => {
isSaveButtonPressed.current = true;
const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(currentAmount.amount));
IOU.setMoneyRequestTaxAmount(transactionID, amountInSmallestCurrencyUnits, true);

IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency || CONST.CURRENCY.USD, true);
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, transaction?.currency || CONST.CURRENCY.USD, true);

if (backTo) {
Navigation.goBack(backTo);
Expand All @@ -126,7 +112,7 @@ function IOURequestStepTaxAmountPage({
// If a reportID exists in the report object, it's because the user started this flow from using the + button in the composer
// inside a report. In this case, the participants can be automatically assigned from the report and the user can skip the participants step and go straight
// to the confirm step.
if (report.reportID) {
if (report?.reportID) {
// TODO: Is this really needed at all?
IOU.setMoneyRequestParticipantsFromReport(transactionID, report);
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID));
Expand All @@ -148,9 +134,9 @@ function IOURequestStepTaxAmountPage({
>
<MoneyRequestAmountForm
isEditing={isEditing}
currency={currency}
amount={transaction.taxAmount}
taxAmount={getTaxAmount(transaction, taxRates.defaultValue)}
currency={transaction?.currency}
amount={transaction?.taxAmount}
taxAmount={getTaxAmount(transaction, taxRates?.defaultValue)}
ref={(e) => (textInput.current = e)}
onCurrencyButtonPress={navigateToCurrencySelectionPage}
onSubmitButtonPress={updateTaxAmount}
Expand All @@ -159,16 +145,17 @@ function IOURequestStepTaxAmountPage({
);
}

IOURequestStepTaxAmountPage.propTypes = propTypes;
IOURequestStepTaxAmountPage.defaultProps = defaultProps;
IOURequestStepTaxAmountPage.displayName = 'IOURequestStepTaxAmountPage';

export default compose(
withWritableReportOrNotFound,
withFullTransactionOrNotFound,
withOnyx({
policy: {
key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`,
},
}),
)(IOURequestStepTaxAmountPage);
const IOURequestStepTaxAmountPageWithOnyx = withOnyx<IOURequestStepTaxAmountPageProps, IOURequestStepTaxAmountPageOnyxProps>({
policy: {
key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`,
},
})(IOURequestStepTaxAmountPage);

// eslint-disable-next-line rulesdir/no-negated-variables
const IOURequestStepTaxAmountPageWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepTaxAmountPageWithOnyx);
// eslint-disable-next-line rulesdir/no-negated-variables
const IOURequestStepTaxAmountPageWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepTaxAmountPageWithWritableReportOrNotFound);

export default IOURequestStepTaxAmountPageWithFullTransactionOrNotFound;
Loading
Loading