From 71d5b83558ca43652eb841897007bc5e391ddb7c Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Wed, 29 Nov 2023 12:43:16 +0100
Subject: [PATCH 01/15] Migrate src/libs/getModalState.js

---
 src/libs/{getModalState.js => getModalState.ts} | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
 rename src/libs/{getModalState.js => getModalState.ts} (57%)

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<Modal> = {};
 
 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<Modal> {
     return modalState;
 }

From 863114e553d487eb4dad45e58c3a40d816b0ba37 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Wed, 29 Nov 2023 12:55:29 +0100
Subject: [PATCH 02/15] Migrate src/libs/NextStepUtils.js

---
 src/libs/{NextStepUtils.js => NextStepUtils.ts} | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
 rename src/libs/{NextStepUtils.js => NextStepUtils.ts} (68%)

diff --git a/src/libs/NextStepUtils.js b/src/libs/NextStepUtils.ts
similarity index 68%
rename from src/libs/NextStepUtils.js
rename to src/libs/NextStepUtils.ts
index 303f9b2a9925..1d99da633a4e 100644
--- a/src/libs/NextStepUtils.js
+++ b/src/libs/NextStepUtils.ts
@@ -1,11 +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[]) {
     let nextStepHTML = '';
 
-    _.each(messageToParse, (part) => {
-        const tagType = part.type || 'span';
+    messages?.forEach((part) => {
+        const tagType = part.type ?? 'span';
         nextStepHTML += `<${tagType}>${Str.safeEscape(part.text)}</${tagType}>`;
     });
 

From 194c1e14690d67ede84df568c613117153bc2eac Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Wed, 29 Nov 2023 13:00:55 +0100
Subject: [PATCH 03/15] Migrate src/libs/HeaderUtils.js

---
 src/libs/{HeaderUtils.js => HeaderUtils.ts} | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)
 rename src/libs/{HeaderUtils.js => HeaderUtils.ts} (75%)

diff --git a/src/libs/HeaderUtils.js b/src/libs/HeaderUtils.ts
similarity index 75%
rename from src/libs/HeaderUtils.js
rename to src/libs/HeaderUtils.ts
index 2edca95ecf74..39dc0bc706e3 100644
--- a/src/libs/HeaderUtils.js
+++ b/src/libs/HeaderUtils.ts
@@ -1,13 +1,17 @@
+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';
 
-/**
- * @param {Object} report
- * @returns {Object} pin/unpin object
- */
-function getPinMenuItem(report) {
+type MenuItem = {
+    icon: string | React.FC<SvgProps>;
+    text: string;
+    onSelected: () => void;
+};
+
+function getPinMenuItem(report: OnyxReport): MenuItem {
     if (!report.isPinned) {
         return {
             icon: Expensicons.Pin,

From 6d2e5009b0bb263b9c3350820d646b6e64373bb8 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Wed, 29 Nov 2023 13:56:18 +0100
Subject: [PATCH 04/15] Migrate src/libs/DistanceRequestUtils.ts

---
 src/libs/DistanceRequestUtils.js | 112 ----------------------------
 src/libs/DistanceRequestUtils.ts | 121 +++++++++++++++++++++++++++++++
 src/libs/HeaderUtils.ts          |   7 +-
 src/types/onyx/Policy.ts         |  21 +++++-
 4 files changed, 145 insertions(+), 116 deletions(-)
 delete mode 100644 src/libs/DistanceRequestUtils.js
 create mode 100644 src/libs/DistanceRequestUtils.ts

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..ad0b814f1e5c
--- /dev/null
+++ b/src/libs/DistanceRequestUtils.ts
@@ -0,0 +1,121 @@
+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: Policy): DefaultMileageRate | null {
+    if (!policy?.customUnits) {
+        return null;
+    }
+
+    const distanceUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
+    if (!distanceUnit) {
+        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');
+    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.ts b/src/libs/HeaderUtils.ts
index 39dc0bc706e3..f7779b6db52f 100644
--- a/src/libs/HeaderUtils.ts
+++ b/src/libs/HeaderUtils.ts
@@ -12,17 +12,18 @@ type MenuItem = {
 };
 
 function getPinMenuItem(report: OnyxReport): MenuItem {
-    if (!report.isPinned) {
+    const isPinned = report?.isPinned;
+    if (!isPinned) {
         return {
             icon: Expensicons.Pin,
             text: Localize.translateLocal('common.pin'),
-            onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)),
+            onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, !!isPinned)),
         };
     }
     return {
         icon: Expensicons.Pin,
         text: Localize.translateLocal('common.unPin'),
-        onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)),
+        onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, isPinned)),
     };
 }
 
diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts
index e6e3240d1b23..e7550713710e 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<string, Rate>;
+};
+
 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<string, unknown>;
+    customUnits?: Record<string, CustomUnit>;
 
     /** 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 {Unit};

From 4de2b6a80b3ab93d5c2b7529328cc8568a797161 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Thu, 30 Nov 2023 15:51:04 +0100
Subject: [PATCH 05/15] Migrate src/libs/shouldReopenOnfido

---
 src/libs/shouldReopenOnfido/index.android.js | 1 -
 src/libs/shouldReopenOnfido/index.android.ts | 5 +++++
 src/libs/shouldReopenOnfido/index.js         | 1 -
 src/libs/shouldReopenOnfido/index.ts         | 5 +++++
 src/libs/shouldReopenOnfido/types.ts         | 3 +++
 src/types/onyx/Policy.ts                     | 2 +-
 6 files changed, 14 insertions(+), 3 deletions(-)
 delete mode 100644 src/libs/shouldReopenOnfido/index.android.js
 create mode 100644 src/libs/shouldReopenOnfido/index.android.ts
 delete mode 100644 src/libs/shouldReopenOnfido/index.js
 create mode 100644 src/libs/shouldReopenOnfido/index.ts
 create mode 100644 src/libs/shouldReopenOnfido/types.ts

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/types/onyx/Policy.ts b/src/types/onyx/Policy.ts
index e7550713710e..a55a7c052b01 100644
--- a/src/types/onyx/Policy.ts
+++ b/src/types/onyx/Policy.ts
@@ -80,4 +80,4 @@ type Policy = {
 
 export default Policy;
 
-export {Unit};
+export type {Unit};

From 478c580550f03227133e416737846873e87cae17 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Thu, 30 Nov 2023 16:51:26 +0100
Subject: [PATCH 06/15] Migrate RenameReceiptFilename migration

---
 src/libs/migrations/RenameReceiptFilename.js | 57 --------------------
 src/libs/migrations/RenameReceiptFilename.ts | 56 +++++++++++++++++++
 2 files changed, 56 insertions(+), 57 deletions(-)
 delete mode 100644 src/libs/migrations/RenameReceiptFilename.js
 create mode 100644 src/libs/migrations/RenameReceiptFilename.ts

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..5c18647ffe57
--- /dev/null
+++ b/src/libs/migrations/RenameReceiptFilename.ts
@@ -0,0 +1,56 @@
+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};
+
+// 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<void>((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<OldTransaction>) => {
+                Onyx.disconnect(connectionID);
+
+                if (!transactions || isEmptyObject(transactions)) {
+                    Log.info('[Migrate Onyx] Skipped migration RenameReceiptFilename because there are no transactions');
+                    return resolve();
+                }
+
+                const transactionArray: Array<OldTransaction | null> = Object.values(transactions);
+                if (!transactionArray?.map((transaction) => transaction?.receiptFilename).filter(Boolean).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<`${typeof ONYXKEYS.COLLECTION.TRANSACTION}${string}`, NullishDeep<OldTransaction>> = {};
+
+                transactionArray?.forEach((transaction) => {
+                    // Do nothing if there is no receiptFilename property
+                    if (!transaction || !('receiptFilename' in transaction)) {
+                        return;
+                    }
+
+                    Log.info(`[Migrate Onyx] Renaming receiptFilename ${transaction?.receiptFilename} to filename`);
+                    dataToSave[`${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();
+                });
+            },
+        });
+    });
+}

From 73e9c92eb423adc27e91155a1e088f2aa940932f Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Thu, 30 Nov 2023 17:05:31 +0100
Subject: [PATCH 07/15] Migrate KeyReportActionsDraftByReportActionID migration

---
 ... KeyReportActionsDraftByReportActionID.ts} | 33 +++++++++++--------
 1 file changed, 19 insertions(+), 14 deletions(-)
 rename src/libs/migrations/{KeyReportActionsDraftByReportActionID.js => KeyReportActionsDraftByReportActionID.ts} (61%)

diff --git a/src/libs/migrations/KeyReportActionsDraftByReportActionID.js b/src/libs/migrations/KeyReportActionsDraftByReportActionID.ts
similarity index 61%
rename from src/libs/migrations/KeyReportActionsDraftByReportActionID.js
rename to src/libs/migrations/KeyReportActionsDraftByReportActionID.ts
index e4b3ebd060f3..944b9d3e5478 100644
--- a/src/libs/migrations/KeyReportActionsDraftByReportActionID.js
+++ b/src/libs/migrations/KeyReportActionsDraftByReportActionID.ts
@@ -1,21 +1,21 @@
-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';
 
 /**
  * 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<void>((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 +24,39 @@ export default function () {
                     return resolve();
                 }
 
-                const newReportActionsDrafts = {};
-                _.each(allReportActionsDrafts, (reportActionDraft, onyxKey) => {
-                    if (!_.isString(reportActionDraft)) {
+                type ReportActionsDraftsKey = `${typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${string}`;
+                const newReportActionsDrafts: Record<ReportActionsDraftsKey, OnyxEntry<ReportActionsDrafts>> = {};
+                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);
             },

From 276eef40cf8706d7c6c7b2744dd0198839c1d76c Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Thu, 30 Nov 2023 17:23:04 +0100
Subject: [PATCH 08/15] Migrate UpdateMultilineInputRange

---
 .../{index.ios.js => index.ios.ts}                 | 11 ++++++-----
 .../{index.js => index.ts}                         | 14 +++++++-------
 src/libs/UpdateMultilineInputRange/types.ts        |  5 +++++
 3 files changed, 18 insertions(+), 12 deletions(-)
 rename src/libs/UpdateMultilineInputRange/{index.ios.js => index.ios.ts} (82%)
 rename src/libs/UpdateMultilineInputRange/{index.js => index.ts} (75%)
 create mode 100644 src/libs/UpdateMultilineInputRange/types.ts

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 75%
rename from src/libs/UpdateMultilineInputRange/index.js
rename to src/libs/UpdateMultilineInputRange/index.ts
index 66fb1889be21..30b98c05744f 100644
--- a/src/libs/UpdateMultilineInputRange/index.js
+++ b/src/libs/UpdateMultilineInputRange/index.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,20 +8,18 @@
  * 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
  */
-// eslint-disable-next-line no-unused-vars
-export default function updateMultilineInputRange(input, shouldAutoFocus = true) {
+const updateMultilineInputRange: UpdateMultilineInputRange = (input) => {
     if (!input) {
         return;
     }
 
-    if (input.value && input.setSelectionRange) {
+    if ('value' in input && input.value && input.setSelectionRange) {
         const length = input.value.length;
         input.setSelectionRange(length, length);
         // 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;

From a313241741f55ae6a38ab31d68d46b1a3ebfbd72 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Fri, 1 Dec 2023 14:24:28 +0100
Subject: [PATCH 09/15] Adjust the code after review

---
 src/libs/DistanceRequestUtils.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts
index ad0b814f1e5c..682567c4c6ba 100644
--- a/src/libs/DistanceRequestUtils.ts
+++ b/src/libs/DistanceRequestUtils.ts
@@ -25,12 +25,12 @@ function getDefaultMileageRate(policy: Policy): DefaultMileageRate | null {
         return null;
     }
 
-    const distanceUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
-    if (!distanceUnit) {
+    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);
+    const distanceRate = Object.values(distanceUnit.rates).find((rate) => rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE);
     if (!distanceRate) {
         return null;
     }

From 17f59baf4cb0b3b46ca18b6e5685418e9763fe90 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Tue, 5 Dec 2023 14:07:31 +0100
Subject: [PATCH 10/15] Add OnyxEntry to functions, adjust ?? to ||

---
 src/libs/DistanceRequestUtils.ts | 6 ++++--
 src/libs/HeaderUtils.ts          | 3 ++-
 src/libs/NextStepUtils.ts        | 5 +++--
 3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts
index 682567c4c6ba..477bfb4b61f9 100644
--- a/src/libs/DistanceRequestUtils.ts
+++ b/src/libs/DistanceRequestUtils.ts
@@ -1,3 +1,4 @@
+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';
@@ -20,7 +21,7 @@ type DefaultMileageRate = {
  * @returns [currency] - The currency associated with the rate.
  * @returns [unit] - The unit of measurement for the distance.
  */
-function getDefaultMileageRate(policy: Policy): DefaultMileageRate | null {
+function getDefaultMileageRate(policy: OnyxEntry<Policy>): DefaultMileageRate | null {
     if (!policy?.customUnits) {
         return null;
     }
@@ -99,7 +100,8 @@ function getDistanceMerchant(
     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} ` : '';
+    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+    const currencySymbol = rate ? CurrencyUtils.getCurrencySymbol(currency) || `${currency} ` : '';
 
     return `${distanceInUnits} ${unitString} @ ${currencySymbol}${ratePerUnit} / ${singularDistanceUnit}`;
 }
diff --git a/src/libs/HeaderUtils.ts b/src/libs/HeaderUtils.ts
index f7779b6db52f..c8dfc20df204 100644
--- a/src/libs/HeaderUtils.ts
+++ b/src/libs/HeaderUtils.ts
@@ -1,3 +1,4 @@
+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';
@@ -11,7 +12,7 @@ type MenuItem = {
     onSelected: () => void;
 };
 
-function getPinMenuItem(report: OnyxReport): MenuItem {
+function getPinMenuItem(report: OnyxEntry<OnyxReport>): MenuItem {
     const isPinned = report?.isPinned;
     if (!isPinned) {
         return {
diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts
index 1d99da633a4e..538e8dbe81f0 100644
--- a/src/libs/NextStepUtils.ts
+++ b/src/libs/NextStepUtils.ts
@@ -5,11 +5,12 @@ type Message = {
     type?: string;
 };
 
-function parseMessage(messages: Message[]) {
+function parseMessage(messages: Message[] | undefined) {
     let nextStepHTML = '';
 
     messages?.forEach((part) => {
-        const tagType = part.type ?? 'span';
+        // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+        const tagType = part.type || 'span';
         nextStepHTML += `<${tagType}>${Str.safeEscape(part.text)}</${tagType}>`;
     });
 

From 688dec676aeda7f4e9a3b18ff8aca2a251e4d34d Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Tue, 5 Dec 2023 14:10:19 +0100
Subject: [PATCH 11/15] Rename '@libs/UpdateMultilineInputRange'

---
 .../index.ios.ts                                                | 0
 .../index.ts                                                    | 0
 .../types.ts                                                    | 0
 src/pages/EditRequestDescriptionPage.js                         | 2 +-
 src/pages/PrivateNotes/PrivateNotesEditPage.js                  | 2 +-
 src/pages/ReportWelcomeMessagePage.js                           | 2 +-
 .../ComposerWithSuggestions/ComposerWithSuggestions.js          | 2 +-
 src/pages/iou/MoneyRequestDescriptionPage.js                    | 2 +-
 src/pages/tasks/NewTaskDescriptionPage.js                       | 2 +-
 src/pages/tasks/TaskDescriptionPage.js                          | 2 +-
 10 files changed, 7 insertions(+), 7 deletions(-)
 rename src/libs/{UpdateMultilineInputRange => updateMultilineInputRange}/index.ios.ts (100%)
 rename src/libs/{UpdateMultilineInputRange => updateMultilineInputRange}/index.ts (100%)
 rename src/libs/{UpdateMultilineInputRange => updateMultilineInputRange}/types.ts (100%)

diff --git a/src/libs/UpdateMultilineInputRange/index.ios.ts b/src/libs/updateMultilineInputRange/index.ios.ts
similarity index 100%
rename from src/libs/UpdateMultilineInputRange/index.ios.ts
rename to src/libs/updateMultilineInputRange/index.ios.ts
diff --git a/src/libs/UpdateMultilineInputRange/index.ts b/src/libs/updateMultilineInputRange/index.ts
similarity index 100%
rename from src/libs/UpdateMultilineInputRange/index.ts
rename to src/libs/updateMultilineInputRange/index.ts
diff --git a/src/libs/UpdateMultilineInputRange/types.ts b/src/libs/updateMultilineInputRange/types.ts
similarity index 100%
rename from src/libs/UpdateMultilineInputRange/types.ts
rename to src/libs/updateMultilineInputRange/types.ts
diff --git a/src/pages/EditRequestDescriptionPage.js b/src/pages/EditRequestDescriptionPage.js
index f6779ac83ead..1f60be85ce94 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 a0e471d00df6..17329139c63f 100644
--- a/src/pages/ReportWelcomeMessagePage.js
+++ b/src/pages/ReportWelcomeMessagePage.js
@@ -14,7 +14,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 ea48f9cc931e..ba50f5503aff 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 43d7b58bfc7f..3937de006d8d 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 002ca2944e52..09ecbc6284e6 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 6901f2562ee3..93d8828ff662 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';

From 30d6aadc7abb3413d10a0c6bed7ab4a02b435a44 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Tue, 5 Dec 2023 14:21:29 +0100
Subject: [PATCH 12/15] Fix getPinMenuItem logic and typecheck failing

---
 src/libs/HeaderUtils.ts | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/src/libs/HeaderUtils.ts b/src/libs/HeaderUtils.ts
index c8dfc20df204..d258cecb3d11 100644
--- a/src/libs/HeaderUtils.ts
+++ b/src/libs/HeaderUtils.ts
@@ -12,18 +12,16 @@ type MenuItem = {
     onSelected: () => void;
 };
 
-function getPinMenuItem(report: OnyxEntry<OnyxReport>): MenuItem {
-    const isPinned = report?.isPinned;
-    if (!isPinned) {
-        return {
-            icon: Expensicons.Pin,
-            text: Localize.translateLocal('common.pin'),
-            onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, !!isPinned)),
-        };
+function getPinMenuItem(report: OnyxEntry<OnyxReport>): MenuItem | undefined {
+    if (!report) {
+        return;
     }
+
+    const isPinned = !!report?.isPinned;
+
     return {
         icon: Expensicons.Pin,
-        text: Localize.translateLocal('common.unPin'),
+        text: Localize.translateLocal(isPinned ? 'common.pin' : 'common.unPin'),
         onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, isPinned)),
     };
 }

From baff909425d1e52a62b10dc6604b451ac2d0a4e2 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Tue, 5 Dec 2023 14:26:43 +0100
Subject: [PATCH 13/15] Remove optional chaining

---
 src/libs/HeaderUtils.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libs/HeaderUtils.ts b/src/libs/HeaderUtils.ts
index d258cecb3d11..57c7bc22a31e 100644
--- a/src/libs/HeaderUtils.ts
+++ b/src/libs/HeaderUtils.ts
@@ -17,7 +17,7 @@ function getPinMenuItem(report: OnyxEntry<OnyxReport>): MenuItem | undefined {
         return;
     }
 
-    const isPinned = !!report?.isPinned;
+    const isPinned = !!report.isPinned;
 
     return {
         icon: Expensicons.Pin,

From c106a013fcc2db3aba1c3f11a89405c44dd0733b Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Thu, 7 Dec 2023 10:00:55 +0100
Subject: [PATCH 14/15] Fix pin menu

---
 src/libs/HeaderUtils.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libs/HeaderUtils.ts b/src/libs/HeaderUtils.ts
index 57c7bc22a31e..6ef8445f707b 100644
--- a/src/libs/HeaderUtils.ts
+++ b/src/libs/HeaderUtils.ts
@@ -21,7 +21,7 @@ function getPinMenuItem(report: OnyxEntry<OnyxReport>): MenuItem | undefined {
 
     return {
         icon: Expensicons.Pin,
-        text: Localize.translateLocal(isPinned ? 'common.pin' : 'common.unPin'),
+        text: Localize.translateLocal(isPinned ? 'common.unPin' : 'common.pin'),
         onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, isPinned)),
     };
 }

From 8f06dadd5cae24fa70de74f1fda8fcc20b96ce23 Mon Sep 17 00:00:00 2001
From: Blazej Kustra <blazej.kustra@swmansion.com>
Date: Fri, 8 Dec 2023 10:12:16 +0100
Subject: [PATCH 15/15] Clean migration files code

---
 .../KeyReportActionsDraftByReportActionID.ts  |  3 ++-
 src/libs/migrations/RenameReceiptFilename.ts  | 27 +++++++++----------
 2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/libs/migrations/KeyReportActionsDraftByReportActionID.ts b/src/libs/migrations/KeyReportActionsDraftByReportActionID.ts
index 944b9d3e5478..1abe5a6114bb 100644
--- a/src/libs/migrations/KeyReportActionsDraftByReportActionID.ts
+++ b/src/libs/migrations/KeyReportActionsDraftByReportActionID.ts
@@ -4,6 +4,8 @@ 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.
  *
@@ -24,7 +26,6 @@ export default function () {
                     return resolve();
                 }
 
-                type ReportActionsDraftsKey = `${typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${string}`;
                 const newReportActionsDrafts: Record<ReportActionsDraftsKey, OnyxEntry<ReportActionsDrafts>> = {};
                 Object.entries(allReportActionsDrafts).forEach(([onyxKey, reportActionDraft]) => {
                     if (typeof reportActionDraft !== 'string') {
diff --git a/src/libs/migrations/RenameReceiptFilename.ts b/src/libs/migrations/RenameReceiptFilename.ts
index 5c18647ffe57..b2c19848aedb 100644
--- a/src/libs/migrations/RenameReceiptFilename.ts
+++ b/src/libs/migrations/RenameReceiptFilename.ts
@@ -6,6 +6,7 @@ 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 () {
@@ -23,25 +24,23 @@ export default function () {
                     return resolve();
                 }
 
-                const transactionArray: Array<OldTransaction | null> = Object.values(transactions);
-                if (!transactionArray?.map((transaction) => transaction?.receiptFilename).filter(Boolean).length) {
+                const transactionsWithReceipt: Array<OldTransaction | null> = 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<`${typeof ONYXKEYS.COLLECTION.TRANSACTION}${string}`, NullishDeep<OldTransaction>> = {};
-
-                transactionArray?.forEach((transaction) => {
-                    // Do nothing if there is no receiptFilename property
-                    if (!transaction || !('receiptFilename' in transaction)) {
-                        return;
+                const dataToSave: Record<TransactionKey, NullishDeep<OldTransaction>> = transactionsWithReceipt?.reduce((result, transaction) => {
+                    if (!transaction) {
+                        return result;
                     }
-
-                    Log.info(`[Migrate Onyx] Renaming receiptFilename ${transaction?.receiptFilename} to filename`);
-                    dataToSave[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`] = {
-                        filename: transaction?.receiptFilename,
-                        receiptFilename: null,
+                    Log.info(`[Migrate Onyx] Renaming receiptFilename ${transaction.receiptFilename} to filename`);
+                    return {
+                        ...result,
+                        [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: {
+                            filename: transaction.receiptFilename,
+                            receiptFilename: null,
+                        },
                     };
                 }, {});
 
