diff --git a/src/libs/DistanceRequestUtils.js b/src/libs/DistanceRequestUtils.js deleted file mode 100644 index 0f994cc54f93..000000000000 --- a/src/libs/DistanceRequestUtils.js +++ /dev/null @@ -1,112 +0,0 @@ -import _ from 'underscore'; -import CONST from '@src/CONST'; -import * as CurrencyUtils from './CurrencyUtils'; -import * as PolicyUtils from './PolicyUtils'; - -/** - * Retrieves the default mileage rate based on a given policy. - * - * @param {Object} policy - The policy from which to extract the default mileage rate. - * @param {Object} [policy.customUnits] - Custom units defined in the policy. - * @param {Object[]} [policy.customUnits.rates] - Rates used in the policy. - * @param {Object} [policy.customUnits.attributes] - attributes on a custom unit - * @param {'mi' | 'km'} [policy.customUnits.attributes.unit] - unit of measurement for the distance - * - * @returns {Object|null} An object containing the rate and unit for the default mileage or null if not found. - * @returns {Number} .rate - The default rate for the mileage. - * @returns {String} .currency - The currency associated with the rate. - * @returns {String} .unit - The unit of measurement for the distance. - */ -const getDefaultMileageRate = (policy) => { - if (!policy || !policy.customUnits) { - return null; - } - - const distanceUnit = _.find(_.values(policy.customUnits), (unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); - if (!distanceUnit) { - return null; - } - - const distanceRate = _.find(_.values(distanceUnit.rates), (rate) => rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE); - if (!distanceRate) { - return null; - } - - return { - rate: distanceRate.rate, - currency: distanceRate.currency, - unit: distanceUnit.attributes.unit, - }; -}; - -/** - * Converts a given distance in meters to the specified unit (kilometers or miles). - * - * @param {Number} distanceInMeters - The distance in meters to be converted. - * @param {'mi' | 'km'} unit - The desired unit of conversion, either 'km' for kilometers or 'mi' for miles. - * - * @returns {Number} The converted distance in the specified unit. - */ -function convertDistanceUnit(distanceInMeters, unit) { - const METERS_TO_KM = 0.001; // 1 kilometer is 1000 meters - const METERS_TO_MILES = 0.000621371; // There are approximately 0.000621371 miles in a meter - - switch (unit) { - case CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS: - return distanceInMeters * METERS_TO_KM; - case CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES: - return distanceInMeters * METERS_TO_MILES; - default: - throw new Error('Unsupported unit. Supported units are "mi" or "km".'); - } -} - -/** - * - * @param {Number} distanceInMeters Distance traveled - * @param {'mi' | 'km'} unit Unit that should be used to display the distance - * @returns {String} The distance in requested units, rounded to 2 decimals - */ -const getRoundedDistanceInUnits = (distanceInMeters, unit) => { - const convertedDistance = convertDistanceUnit(distanceInMeters, unit); - return convertedDistance.toFixed(2); -}; - -/** - * - * @param {boolean} hasRoute Whether the route exists for the distance request - * @param {Number} distanceInMeters Distance traveled - * @param {'mi' | 'km'} unit Unit that should be used to display the distance - * @param {Number} rate Expensable amount allowed per unit - * @param {String} currency The currency associated with the rate - * @param {Function} translate Translate function - * @param {Function} toLocaleDigit Function to convert to localized digit - * @returns {String} A string that describes the distance traveled and the rate used for expense calculation - */ -const getDistanceMerchant = (hasRoute, distanceInMeters, unit, rate, currency, translate, toLocaleDigit) => { - const distanceInUnits = hasRoute ? getRoundedDistanceInUnits(distanceInMeters, unit) : translate('common.tbd'); - - const distanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.miles') : translate('common.kilometers'); - const singularDistanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.mile') : translate('common.kilometer'); - const unitString = distanceInUnits === 1 ? singularDistanceUnit : distanceUnit; - const ratePerUnit = rate ? PolicyUtils.getUnitRateValue({rate}, toLocaleDigit) : translate('common.tbd'); - const currencySymbol = rate ? CurrencyUtils.getCurrencySymbol(currency) || `${currency} ` : ''; - - return `${distanceInUnits} ${unitString} @ ${currencySymbol}${ratePerUnit} / ${singularDistanceUnit}`; -}; - -/** - * Calculates the request amount based on distance, unit, and rate. - * - * @param {Number} distance - The distance traveled in meters - * @param {'mi' | 'km'} unit - The unit of measurement for the distance - * @param {Number} rate - Rate used for calculating the request amount - * @returns {Number} The computed request amount (rounded) in "cents". - */ -const getDistanceRequestAmount = (distance, unit, rate) => { - const convertedDistance = convertDistanceUnit(distance, unit); - const roundedDistance = convertedDistance.toFixed(2); - return Math.round(roundedDistance * rate); -}; - -export default {getDefaultMileageRate, getDistanceMerchant, getDistanceRequestAmount}; diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts new file mode 100644 index 000000000000..477bfb4b61f9 --- /dev/null +++ b/src/libs/DistanceRequestUtils.ts @@ -0,0 +1,123 @@ +import {OnyxEntry} from 'react-native-onyx'; +import type {LocaleContextProps} from '@components/LocaleContextProvider'; +import CONST from '@src/CONST'; +import Policy, {Unit} from '@src/types/onyx/Policy'; +import * as CurrencyUtils from './CurrencyUtils'; +import * as PolicyUtils from './PolicyUtils'; + +type DefaultMileageRate = { + rate: number; + currency: string; + unit: Unit; +}; + +/** + * Retrieves the default mileage rate based on a given policy. + * + * @param policy - The policy from which to extract the default mileage rate. + * + * @returns An object containing the rate and unit for the default mileage or null if not found. + * @returns [rate] - The default rate for the mileage. + * @returns [currency] - The currency associated with the rate. + * @returns [unit] - The unit of measurement for the distance. + */ +function getDefaultMileageRate(policy: OnyxEntry): DefaultMileageRate | null { + if (!policy?.customUnits) { + return null; + } + + const distanceUnit = Object.values(policy.customUnits).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); + if (!distanceUnit?.rates) { + return null; + } + + const distanceRate = Object.values(distanceUnit.rates).find((rate) => rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE); + if (!distanceRate) { + return null; + } + + return { + rate: distanceRate.rate, + currency: distanceRate.currency, + unit: distanceUnit.attributes.unit, + }; +} + +/** + * Converts a given distance in meters to the specified unit (kilometers or miles). + * + * @param distanceInMeters - The distance in meters to be converted. + * @param unit - The desired unit of conversion, either 'km' for kilometers or 'mi' for miles. + * + * @returns The converted distance in the specified unit. + */ +function convertDistanceUnit(distanceInMeters: number, unit: Unit): number { + const METERS_TO_KM = 0.001; // 1 kilometer is 1000 meters + const METERS_TO_MILES = 0.000621371; // There are approximately 0.000621371 miles in a meter + + switch (unit) { + case CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS: + return distanceInMeters * METERS_TO_KM; + case CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES: + return distanceInMeters * METERS_TO_MILES; + default: + throw new Error('Unsupported unit. Supported units are "mi" or "km".'); + } +} + +/** + * @param distanceInMeters Distance traveled + * @param unit Unit that should be used to display the distance + * @returns The distance in requested units, rounded to 2 decimals + */ +function getRoundedDistanceInUnits(distanceInMeters: number, unit: Unit): string { + const convertedDistance = convertDistanceUnit(distanceInMeters, unit); + return convertedDistance.toFixed(2); +} + +/** + * @param hasRoute Whether the route exists for the distance request + * @param distanceInMeters Distance traveled + * @param unit Unit that should be used to display the distance + * @param rate Expensable amount allowed per unit + * @param currency The currency associated with the rate + * @param translate Translate function + * @param toLocaleDigit Function to convert to localized digit + * @returns A string that describes the distance traveled and the rate used for expense calculation + */ +function getDistanceMerchant( + hasRoute: boolean, + distanceInMeters: number, + unit: Unit, + rate: number, + currency: string, + translate: LocaleContextProps['translate'], + toLocaleDigit: LocaleContextProps['toLocaleDigit'], +): string { + const distanceInUnits = hasRoute ? getRoundedDistanceInUnits(distanceInMeters, unit) : translate('common.tbd'); + + const distanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.miles') : translate('common.kilometers'); + const singularDistanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.mile') : translate('common.kilometer'); + const unitString = distanceInUnits === '1' ? singularDistanceUnit : distanceUnit; + const ratePerUnit = rate ? PolicyUtils.getUnitRateValue({rate}, toLocaleDigit) : translate('common.tbd'); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const currencySymbol = rate ? CurrencyUtils.getCurrencySymbol(currency) || `${currency} ` : ''; + + return `${distanceInUnits} ${unitString} @ ${currencySymbol}${ratePerUnit} / ${singularDistanceUnit}`; +} + +/** + * Calculates the request amount based on distance, unit, and rate. + * + * @param distance - The distance traveled in meters + * @param unit - The unit of measurement for the distance + * @param rate - Rate used for calculating the request amount + * @returns The computed request amount (rounded) in "cents". + */ +function getDistanceRequestAmount(distance: number, unit: Unit, rate: number): number { + const convertedDistance = convertDistanceUnit(distance, unit); + const roundedDistance = parseFloat(convertedDistance.toFixed(2)); + return Math.round(roundedDistance * rate); +} + +export default {getDefaultMileageRate, getDistanceMerchant, getDistanceRequestAmount}; diff --git a/src/libs/HeaderUtils.js b/src/libs/HeaderUtils.js deleted file mode 100644 index 2edca95ecf74..000000000000 --- a/src/libs/HeaderUtils.js +++ /dev/null @@ -1,28 +0,0 @@ -import * as Expensicons from '@components/Icon/Expensicons'; -import * as Report from './actions/Report'; -import * as Session from './actions/Session'; -import * as Localize from './Localize'; - -/** - * @param {Object} report - * @returns {Object} pin/unpin object - */ -function getPinMenuItem(report) { - if (!report.isPinned) { - return { - icon: Expensicons.Pin, - text: Localize.translateLocal('common.pin'), - onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), - }; - } - return { - icon: Expensicons.Pin, - text: Localize.translateLocal('common.unPin'), - onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), - }; -} - -export { - // eslint-disable-next-line import/prefer-default-export - getPinMenuItem, -}; diff --git a/src/libs/HeaderUtils.ts b/src/libs/HeaderUtils.ts new file mode 100644 index 000000000000..6ef8445f707b --- /dev/null +++ b/src/libs/HeaderUtils.ts @@ -0,0 +1,32 @@ +import {OnyxEntry} from 'react-native-onyx'; +import {SvgProps} from 'react-native-svg'; +import * as Expensicons from '@components/Icon/Expensicons'; +import OnyxReport from '@src/types/onyx/Report'; +import * as Report from './actions/Report'; +import * as Session from './actions/Session'; +import * as Localize from './Localize'; + +type MenuItem = { + icon: string | React.FC; + text: string; + onSelected: () => void; +}; + +function getPinMenuItem(report: OnyxEntry): MenuItem | undefined { + if (!report) { + return; + } + + const isPinned = !!report.isPinned; + + return { + icon: Expensicons.Pin, + text: Localize.translateLocal(isPinned ? 'common.unPin' : 'common.pin'), + onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, isPinned)), + }; +} + +export { + // eslint-disable-next-line import/prefer-default-export + getPinMenuItem, +}; diff --git a/src/libs/NextStepUtils.js b/src/libs/NextStepUtils.ts similarity index 65% rename from src/libs/NextStepUtils.js rename to src/libs/NextStepUtils.ts index 303f9b2a9925..538e8dbe81f0 100644 --- a/src/libs/NextStepUtils.js +++ b/src/libs/NextStepUtils.ts @@ -1,10 +1,15 @@ import Str from 'expensify-common/lib/str'; -import _ from 'underscore'; -function parseMessage(messageToParse) { +type Message = { + text: string; + type?: string; +}; + +function parseMessage(messages: Message[] | undefined) { let nextStepHTML = ''; - _.each(messageToParse, (part) => { + messages?.forEach((part) => { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const tagType = part.type || 'span'; nextStepHTML += `<${tagType}>${Str.safeEscape(part.text)}`; }); diff --git a/src/libs/getModalState.js b/src/libs/getModalState.ts similarity index 57% rename from src/libs/getModalState.js rename to src/libs/getModalState.ts index 30ff8499809a..47aa0c406b29 100644 --- a/src/libs/getModalState.js +++ b/src/libs/getModalState.ts @@ -1,12 +1,13 @@ -import Onyx from 'react-native-onyx'; +import Onyx, {OnyxEntry} from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; +import Modal from '@src/types/onyx/Modal'; -let modalState = {}; +let modalState: OnyxEntry = {}; Onyx.connect({ key: ONYXKEYS.MODAL, - callback: (val) => { - modalState = val; + callback: (value) => { + modalState = value; }, }); @@ -14,8 +15,7 @@ Onyx.connect({ * Returns the modal state from onyx. * Note: You should use the HOCs/hooks to get onyx data, instead of using this directly. * A valid use case to use this is if the value is only needed once for an initial value. - * @returns {Object} */ -export default function getModalState() { +export default function getModalState(): OnyxEntry { return modalState; } diff --git a/src/libs/migrations/KeyReportActionsDraftByReportActionID.js b/src/libs/migrations/KeyReportActionsDraftByReportActionID.ts similarity index 62% rename from src/libs/migrations/KeyReportActionsDraftByReportActionID.js rename to src/libs/migrations/KeyReportActionsDraftByReportActionID.ts index e4b3ebd060f3..1abe5a6114bb 100644 --- a/src/libs/migrations/KeyReportActionsDraftByReportActionID.js +++ b/src/libs/migrations/KeyReportActionsDraftByReportActionID.ts @@ -1,21 +1,23 @@ -import Onyx from 'react-native-onyx'; -import _ from 'underscore'; +import Onyx, {OnyxEntry} from 'react-native-onyx'; import Log from '@libs/Log'; import ONYXKEYS from '@src/ONYXKEYS'; +import {ReportActionsDrafts} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +type ReportActionsDraftsKey = `${typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${string}`; /** * This migration updates reportActionsDrafts data to be keyed by reportActionID. * * Before: reportActionsDrafts_reportID_reportActionID: value * After: reportActionsDrafts_reportID: {[reportActionID]: value} - * - * @returns {Promise} */ export default function () { - return new Promise((resolve) => { + return new Promise((resolve) => { const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS, waitForCollectionCallback: true, + // eslint-disable-next-line @typescript-eslint/no-misused-promises callback: (allReportActionsDrafts) => { Onyx.disconnect(connectionID); @@ -24,34 +26,38 @@ export default function () { return resolve(); } - const newReportActionsDrafts = {}; - _.each(allReportActionsDrafts, (reportActionDraft, onyxKey) => { - if (!_.isString(reportActionDraft)) { + const newReportActionsDrafts: Record> = {}; + Object.entries(allReportActionsDrafts).forEach(([onyxKey, reportActionDraft]) => { + if (typeof reportActionDraft !== 'string') { return; } - newReportActionsDrafts[onyxKey] = null; + newReportActionsDrafts[onyxKey as ReportActionsDraftsKey] = null; - if (_.isEmpty(reportActionDraft)) { + if (isEmptyObject(reportActionDraft)) { return; } const reportActionID = onyxKey.split('_').pop(); - const newOnyxKey = onyxKey.replace(`_${reportActionID}`, ''); + const newOnyxKey = onyxKey.replace(`_${reportActionID}`, '') as ReportActionsDraftsKey; + + if (!reportActionID) { + return; + } // If newReportActionsDrafts[newOnyxKey] isn't set, fall back on the migrated draft if there is one - const currentActionsDrafts = newReportActionsDrafts[newOnyxKey] || allReportActionsDrafts[newOnyxKey]; + const currentActionsDrafts = newReportActionsDrafts[newOnyxKey] ?? allReportActionsDrafts[newOnyxKey]; newReportActionsDrafts[newOnyxKey] = { ...currentActionsDrafts, [reportActionID]: reportActionDraft, }; }); - if (_.isEmpty(newReportActionsDrafts)) { + if (isEmptyObject(newReportActionsDrafts)) { Log.info('[Migrate Onyx] Skipped migration KeyReportActionsDraftByReportActionID because there are no actions drafts to migrate'); return resolve(); } - Log.info(`[Migrate Onyx] Re-keying reportActionsDrafts by reportActionID for ${_.keys(newReportActionsDrafts).length} actions drafts`); + Log.info(`[Migrate Onyx] Re-keying reportActionsDrafts by reportActionID for ${Object.keys(newReportActionsDrafts).length} actions drafts`); // eslint-disable-next-line rulesdir/prefer-actions-set-data return Onyx.multiSet(newReportActionsDrafts).then(resolve); }, diff --git a/src/libs/migrations/RenameReceiptFilename.js b/src/libs/migrations/RenameReceiptFilename.js deleted file mode 100644 index 2fcd9662a993..000000000000 --- a/src/libs/migrations/RenameReceiptFilename.js +++ /dev/null @@ -1,57 +0,0 @@ -import lodashHas from 'lodash/has'; -import Onyx from 'react-native-onyx'; -import _ from 'underscore'; -import Log from '@libs/Log'; -import ONYXKEYS from '@src/ONYXKEYS'; - -// This migration changes the property name on a transaction from receiptFilename to filename so that it matches what is stored in the database -export default function () { - return new Promise((resolve) => { - // Connect to the TRANSACTION collection key in Onyx to get all of the stored transactions. - // Go through each transaction and change the property name - const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.TRANSACTION, - waitForCollectionCallback: true, - callback: (transactions) => { - Onyx.disconnect(connectionID); - - if (!transactions || transactions.length === 0) { - Log.info('[Migrate Onyx] Skipped migration RenameReceiptFilename because there are no transactions'); - return resolve(); - } - - if (!_.compact(_.pluck(transactions, 'receiptFilename')).length) { - Log.info('[Migrate Onyx] Skipped migration RenameReceiptFilename because there were no transactions with the receiptFilename property'); - return resolve(); - } - - Log.info('[Migrate Onyx] Running RenameReceiptFilename migration'); - - const dataToSave = _.reduce( - transactions, - (result, transaction) => { - // Do nothing if there is no receiptFilename property - if (!lodashHas(transaction, 'receiptFilename')) { - return result; - } - Log.info(`[Migrate Onyx] Renaming receiptFilename ${transaction.receiptFilename} to filename`); - return { - ...result, - [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: { - filename: transaction.receiptFilename, - receiptFilename: null, - }, - }; - }, - {}, - ); - - // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.mergeCollection(ONYXKEYS.COLLECTION.TRANSACTION, dataToSave).then(() => { - Log.info(`[Migrate Onyx] Ran migration RenameReceiptFilename and renamed ${_.size(dataToSave)} properties`); - resolve(); - }); - }, - }); - }); -} diff --git a/src/libs/migrations/RenameReceiptFilename.ts b/src/libs/migrations/RenameReceiptFilename.ts new file mode 100644 index 000000000000..b2c19848aedb --- /dev/null +++ b/src/libs/migrations/RenameReceiptFilename.ts @@ -0,0 +1,55 @@ +import Onyx from 'react-native-onyx'; +import {NullishDeep, OnyxCollection} from 'react-native-onyx/lib/types'; +import Log from '@libs/Log'; +import ONYXKEYS from '@src/ONYXKEYS'; +import Transaction from '@src/types/onyx/Transaction'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +type OldTransaction = Transaction & {receiptFilename?: string}; +type TransactionKey = `${typeof ONYXKEYS.COLLECTION.TRANSACTION}${string}`; + +// This migration changes the property name on a transaction from receiptFilename to filename so that it matches what is stored in the database +export default function () { + return new Promise((resolve) => { + // Connect to the TRANSACTION collection key in Onyx to get all of the stored transactions. + // Go through each transaction and change the property name + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.TRANSACTION, + waitForCollectionCallback: true, + callback: (transactions: OnyxCollection) => { + Onyx.disconnect(connectionID); + + if (!transactions || isEmptyObject(transactions)) { + Log.info('[Migrate Onyx] Skipped migration RenameReceiptFilename because there are no transactions'); + return resolve(); + } + + 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(); + } + Log.info('[Migrate Onyx] Running RenameReceiptFilename migration'); + const dataToSave: Record> = transactionsWithReceipt?.reduce((result, transaction) => { + if (!transaction) { + return result; + } + Log.info(`[Migrate Onyx] Renaming receiptFilename ${transaction.receiptFilename} to filename`); + return { + ...result, + [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: { + filename: transaction.receiptFilename, + receiptFilename: null, + }, + }; + }, {}); + + // eslint-disable-next-line rulesdir/prefer-actions-set-data + Onyx.mergeCollection(ONYXKEYS.COLLECTION.TRANSACTION, dataToSave).then(() => { + Log.info(`[Migrate Onyx] Ran migration RenameReceiptFilename and renamed ${Object.keys(dataToSave)?.length} properties`); + resolve(); + }); + }, + }); + }); +} diff --git a/src/libs/shouldReopenOnfido/index.android.js b/src/libs/shouldReopenOnfido/index.android.js deleted file mode 100644 index ff3177babdde..000000000000 --- a/src/libs/shouldReopenOnfido/index.android.js +++ /dev/null @@ -1 +0,0 @@ -export default true; diff --git a/src/libs/shouldReopenOnfido/index.android.ts b/src/libs/shouldReopenOnfido/index.android.ts new file mode 100644 index 000000000000..11f562575b08 --- /dev/null +++ b/src/libs/shouldReopenOnfido/index.android.ts @@ -0,0 +1,5 @@ +import ShouldReopenOnfido from './types'; + +const shouldReopenOnfido: ShouldReopenOnfido = true; + +export default shouldReopenOnfido; diff --git a/src/libs/shouldReopenOnfido/index.js b/src/libs/shouldReopenOnfido/index.js deleted file mode 100644 index 33136544dba2..000000000000 --- a/src/libs/shouldReopenOnfido/index.js +++ /dev/null @@ -1 +0,0 @@ -export default false; diff --git a/src/libs/shouldReopenOnfido/index.ts b/src/libs/shouldReopenOnfido/index.ts new file mode 100644 index 000000000000..24322b57df19 --- /dev/null +++ b/src/libs/shouldReopenOnfido/index.ts @@ -0,0 +1,5 @@ +import ShouldReopenOnfido from './types'; + +const shouldReopenOnfido: ShouldReopenOnfido = false; + +export default shouldReopenOnfido; diff --git a/src/libs/shouldReopenOnfido/types.ts b/src/libs/shouldReopenOnfido/types.ts new file mode 100644 index 000000000000..365fb95bb333 --- /dev/null +++ b/src/libs/shouldReopenOnfido/types.ts @@ -0,0 +1,3 @@ +type ShouldReopenOnfido = boolean; + +export default ShouldReopenOnfido; diff --git a/src/libs/UpdateMultilineInputRange/index.ios.js b/src/libs/updateMultilineInputRange/index.ios.ts similarity index 82% rename from src/libs/UpdateMultilineInputRange/index.ios.js rename to src/libs/updateMultilineInputRange/index.ios.ts index 4c10f768a2a2..cbe271162372 100644 --- a/src/libs/UpdateMultilineInputRange/index.ios.js +++ b/src/libs/updateMultilineInputRange/index.ios.ts @@ -1,3 +1,5 @@ +import UpdateMultilineInputRange from './types'; + /** * Place the cursor at the end of the value (if there is a value in the input). * @@ -6,11 +8,8 @@ * focus. This provides a better user experience in cases where the text in the field has to be edited. The auto- * scroll behaviour works on all platforms except iOS native. * See https://github.com/Expensify/App/issues/20836 for more details. - * - * @param {Object} input the input element - * @param {boolean} shouldAutoFocus */ -export default function updateMultilineInputRange(input, shouldAutoFocus = true) { +const updateMultilineInputRange: UpdateMultilineInputRange = (input, shouldAutoFocus = true) => { if (!input) { return; } @@ -23,4 +22,6 @@ export default function updateMultilineInputRange(input, shouldAutoFocus = true) if (shouldAutoFocus) { input.focus(); } -} +}; + +export default updateMultilineInputRange; diff --git a/src/libs/UpdateMultilineInputRange/index.js b/src/libs/updateMultilineInputRange/index.ts similarity index 83% rename from src/libs/UpdateMultilineInputRange/index.js rename to src/libs/updateMultilineInputRange/index.ts index 7de700fe7636..062a7a80eeaa 100644 --- a/src/libs/UpdateMultilineInputRange/index.js +++ b/src/libs/updateMultilineInputRange/index.ts @@ -1,4 +1,5 @@ import * as Browser from '@libs/Browser'; +import UpdateMultilineInputRange from './types'; /** * Place the cursor at the end of the value (if there is a value in the input). @@ -8,16 +9,13 @@ import * as Browser from '@libs/Browser'; * focus. This provides a better user experience in cases where the text in the field has to be edited. The auto- * scroll behaviour works on all platforms except iOS native. * See https://github.com/Expensify/App/issues/20836 for more details. - * - * @param {Object} input the input element - * @param {boolean} shouldAutoFocus */ -export default function updateMultilineInputRange(input, shouldAutoFocus = true) { +const updateMultilineInputRange: UpdateMultilineInputRange = (input, shouldAutoFocus = true) => { if (!input) { return; } - if (input.value && input.setSelectionRange) { + if ('value' in input && input.value && input.setSelectionRange) { const length = input.value.length; // For mobile Safari, updating the selection prop on an unfocused input will cause it to automatically gain focus @@ -30,4 +28,6 @@ export default function updateMultilineInputRange(input, shouldAutoFocus = true) // eslint-disable-next-line no-param-reassign input.scrollTop = input.scrollHeight; } -} +}; + +export default updateMultilineInputRange; diff --git a/src/libs/updateMultilineInputRange/types.ts b/src/libs/updateMultilineInputRange/types.ts new file mode 100644 index 000000000000..95b5a8bce744 --- /dev/null +++ b/src/libs/updateMultilineInputRange/types.ts @@ -0,0 +1,5 @@ +import {TextInput} from 'react-native'; + +type UpdateMultilineInputRange = (input: HTMLInputElement | TextInput, shouldAutoFocus?: boolean) => void; + +export default UpdateMultilineInputRange; diff --git a/src/pages/EditRequestDescriptionPage.js b/src/pages/EditRequestDescriptionPage.js index caf7571c8719..23b411ee47c4 100644 --- a/src/pages/EditRequestDescriptionPage.js +++ b/src/pages/EditRequestDescriptionPage.js @@ -9,7 +9,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; import useLocalize from '@hooks/useLocalize'; import * as Browser from '@libs/Browser'; -import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.js b/src/pages/PrivateNotes/PrivateNotesEditPage.js index 2c3064d199ef..dce572c7dd6c 100644 --- a/src/pages/PrivateNotes/PrivateNotesEditPage.js +++ b/src/pages/PrivateNotes/PrivateNotesEditPage.js @@ -19,7 +19,7 @@ import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; -import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import withReportAndPrivateNotesOrNotFound from '@pages/home/report/withReportAndPrivateNotesOrNotFound'; import personalDetailsPropType from '@pages/personalDetailsPropType'; import reportPropTypes from '@pages/reportPropTypes'; diff --git a/src/pages/ReportWelcomeMessagePage.js b/src/pages/ReportWelcomeMessagePage.js index fcf9da89ad69..957c3da9c86b 100644 --- a/src/pages/ReportWelcomeMessagePage.js +++ b/src/pages/ReportWelcomeMessagePage.js @@ -15,7 +15,7 @@ import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; -import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import useThemeStyles from '@styles/useThemeStyles'; import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index f99bd7ab7d9d..f5a321f72799 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -22,7 +22,7 @@ import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManag import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as SuggestionUtils from '@libs/SuggestionUtils'; -import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; import SilentCommentUpdater from '@pages/home/report/ReportActionCompose/SilentCommentUpdater'; import Suggestions from '@pages/home/report/ReportActionCompose/Suggestions'; diff --git a/src/pages/iou/MoneyRequestDescriptionPage.js b/src/pages/iou/MoneyRequestDescriptionPage.js index fc0ef88febee..4bfcc7b5f12d 100644 --- a/src/pages/iou/MoneyRequestDescriptionPage.js +++ b/src/pages/iou/MoneyRequestDescriptionPage.js @@ -15,7 +15,7 @@ import * as IOU from '@libs/actions/IOU'; import * as Browser from '@libs/Browser'; import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; import Navigation from '@libs/Navigation/Navigation'; -import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/pages/tasks/NewTaskDescriptionPage.js b/src/pages/tasks/NewTaskDescriptionPage.js index dfb77219ae24..b9a569646148 100644 --- a/src/pages/tasks/NewTaskDescriptionPage.js +++ b/src/pages/tasks/NewTaskDescriptionPage.js @@ -13,7 +13,7 @@ import useAutoFocusInput from '@hooks/useAutoFocusInput'; import * as Browser from '@libs/Browser'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; -import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import useThemeStyles from '@styles/useThemeStyles'; import * as Task from '@userActions/Task'; import CONST from '@src/CONST'; diff --git a/src/pages/tasks/TaskDescriptionPage.js b/src/pages/tasks/TaskDescriptionPage.js index a2f908e2596e..9419610e379d 100644 --- a/src/pages/tasks/TaskDescriptionPage.js +++ b/src/pages/tasks/TaskDescriptionPage.js @@ -16,7 +16,7 @@ import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; -import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; import reportPropTypes from '@pages/reportPropTypes'; import useThemeStyles from '@styles/useThemeStyles'; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index e6e3240d1b23..a55a7c052b01 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -2,6 +2,23 @@ import {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import * as OnyxCommon from './OnyxCommon'; +type Unit = 'mi' | 'km'; + +type Rate = { + name: string; + rate: number; + currency: string; +}; + +type CustomUnit = { + customUnitID?: string; + name?: string; + attributes: { + unit: Unit; + }; + rates?: Record; +}; + type Policy = { /** The ID of the policy */ id: string; @@ -43,7 +60,7 @@ type Policy = { lastModified?: string; /** The custom units data for this policy */ - customUnits?: Record; + customUnits?: Record; /** Whether chat rooms can be created and used on this policy. Enabled manually by CQ/JS snippet. Always true for free policies. */ areChatRoomsEnabled: boolean; @@ -62,3 +79,5 @@ type Policy = { }; export default Policy; + +export type {Unit};