From 71f69fb3b8c49eaf46061dcb8b616cde8f4dad78 Mon Sep 17 00:00:00 2001
From: Kevin Brian Bader <kevin.bader96@gmail.com>
Date: Sat, 20 Dec 2025 16:33:28 -0800
Subject: [PATCH 1/3] refactoring: isPercentageMode to generic prop

---
 .../BaseSelectionListWithSections.tsx                       | 6 +++---
 src/components/SelectionListWithSections/index.tsx          | 5 ++---
 src/components/SelectionListWithSections/types.ts           | 4 ++--
 src/pages/iou/SplitPercentageList.tsx                       | 2 +-
 4 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/src/components/SelectionListWithSections/BaseSelectionListWithSections.tsx b/src/components/SelectionListWithSections/BaseSelectionListWithSections.tsx
index 356eaf5e68a3..1bccd9a5d0e1 100644
--- a/src/components/SelectionListWithSections/BaseSelectionListWithSections.tsx
+++ b/src/components/SelectionListWithSections/BaseSelectionListWithSections.tsx
@@ -145,7 +145,7 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
     shouldHighlightSelectedItem = true,
     shouldDisableHoverStyle = false,
     setShouldDisableHoverStyle = () => {},
-    isPercentageMode,
+    shouldSkipContentHeaderHeightOffset,
     ref,
 }: SelectionListProps<TItem>) {
     const styles = useThemeStyles();
@@ -357,8 +357,8 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
             }
 
             let viewOffset = variables.contentHeaderHeight - viewOffsetToKeepFocusedItemAtTopOfViewableArea;
-            // Remove contentHeaderHeight from viewOffset calculation if isPercentageMode (for scroll offset calculation on native)
-            if (isPercentageMode) {
+            // Skip contentHeaderHeight for native split expense tabs scroll correction
+            if (shouldSkipContentHeaderHeightOffset) {
                 viewOffset = viewOffsetToKeepFocusedItemAtTopOfViewableArea;
             }
             listRef.current.scrollToLocation({sectionIndex, itemIndex, animated, viewOffset});
diff --git a/src/components/SelectionListWithSections/index.tsx b/src/components/SelectionListWithSections/index.tsx
index 5c2cbe9346df..f1374774545c 100644
--- a/src/components/SelectionListWithSections/index.tsx
+++ b/src/components/SelectionListWithSections/index.tsx
@@ -107,9 +107,8 @@ function SelectionListWithSections<TItem extends ListItem>({onScroll, shouldHide
             isRowMultilineSupported
             shouldDisableHoverStyle={shouldDisableHoverStyle}
             setShouldDisableHoverStyle={setShouldDisableHoverStyle}
-            // We only allow the prop to pass on Native (for scroll offset calculation)
-            // web should be false by default since there are no issues on web
-            isPercentageMode={false}
+            // Web doesn't require scroll offset correction, only native does
+            shouldSkipContentHeaderHeightOffset={false}
         />
     );
 }
diff --git a/src/components/SelectionListWithSections/types.ts b/src/components/SelectionListWithSections/types.ts
index 9ad24ea2a7da..2112c8504520 100644
--- a/src/components/SelectionListWithSections/types.ts
+++ b/src/components/SelectionListWithSections/types.ts
@@ -1089,8 +1089,8 @@ type SelectionListProps<TItem extends ListItem> = Partial<ChildrenProps> & {
     shouldDisableHoverStyle?: boolean;
     setShouldDisableHoverStyle?: React.Dispatch<React.SetStateAction<boolean>>;
 
-    /** Whether the list is percentage mode (for scroll offset calculation) */
-    isPercentageMode?: boolean;
+    /** When true, skips the contentHeaderHeight from the viewOffset calculation during scroll-to-index. Only needed on native platforms for split expense tabs (Amount/Percentage/Date) scroll correction. Web should always pass false. */
+    shouldSkipContentHeaderHeightOffset?: boolean;
 } & TRightHandSideComponent<TItem>;
 
 type SelectionListHandle = {
diff --git a/src/pages/iou/SplitPercentageList.tsx b/src/pages/iou/SplitPercentageList.tsx
index af796b288ed0..9a3281b2636b 100644
--- a/src/pages/iou/SplitPercentageList.tsx
+++ b/src/pages/iou/SplitPercentageList.tsx
@@ -59,7 +59,7 @@ function SplitPercentageList({sections, initiallyFocusedOptionKey, onSelectRow,
             shouldPreventDefaultFocusOnSelectRow
             removeClippedSubviews={false}
             shouldHideListOnInitialRender={false}
-            isPercentageMode
+            shouldSkipContentHeaderHeightOffset
         />
     );
 }

From 517eb0294cbddfe296cdba7f99b29e213cfa7224 Mon Sep 17 00:00:00 2001
From: Kevin Brian Bader <kevin.bader96@gmail.com>
Date: Sat, 20 Dec 2025 16:36:19 -0800
Subject: [PATCH 2/3] refactoring: remove displayName references

---
 .../SplitExpense/SplitAmountDisplay.tsx                         | 2 --
 .../SelectionListWithSections/SplitExpense/SplitAmountInput.tsx | 2 --
 .../SplitExpense/SplitPercentageDisplay.tsx                     | 2 --
 .../SplitExpense/SplitPercentageInput.tsx                       | 2 --
 src/components/SelectionListWithSections/SplitListItemInput.tsx | 2 --
 5 files changed, 10 deletions(-)

diff --git a/src/components/SelectionListWithSections/SplitExpense/SplitAmountDisplay.tsx b/src/components/SelectionListWithSections/SplitExpense/SplitAmountDisplay.tsx
index 1035934ab507..c781fd39effc 100644
--- a/src/components/SelectionListWithSections/SplitExpense/SplitAmountDisplay.tsx
+++ b/src/components/SelectionListWithSections/SplitExpense/SplitAmountDisplay.tsx
@@ -42,6 +42,4 @@ function SplitAmountDisplay({splitItem, contentWidth = '100%', shouldRemoveSpaci
     );
 }
 
-SplitAmountDisplay.displayName = 'SplitAmountDisplay';
-
 export default SplitAmountDisplay;
diff --git a/src/components/SelectionListWithSections/SplitExpense/SplitAmountInput.tsx b/src/components/SelectionListWithSections/SplitExpense/SplitAmountInput.tsx
index 73a9ef73308e..79a322e41ecb 100644
--- a/src/components/SelectionListWithSections/SplitExpense/SplitAmountInput.tsx
+++ b/src/components/SelectionListWithSections/SplitExpense/SplitAmountInput.tsx
@@ -65,6 +65,4 @@ function SplitAmountInput({splitItem, formattedOriginalAmount, contentWidth, onS
     );
 }
 
-SplitAmountInput.displayName = 'SplitAmountInput';
-
 export default SplitAmountInput;
diff --git a/src/components/SelectionListWithSections/SplitExpense/SplitPercentageDisplay.tsx b/src/components/SelectionListWithSections/SplitExpense/SplitPercentageDisplay.tsx
index cbd05b5ba34b..532296ecbc5d 100644
--- a/src/components/SelectionListWithSections/SplitExpense/SplitPercentageDisplay.tsx
+++ b/src/components/SelectionListWithSections/SplitExpense/SplitPercentageDisplay.tsx
@@ -27,6 +27,4 @@ function SplitPercentageDisplay({splitItem, contentWidth}: SplitPercentageDispla
     );
 }
 
-SplitPercentageDisplay.displayName = 'SplitPercentageDisplay';
-
 export default SplitPercentageDisplay;
diff --git a/src/components/SelectionListWithSections/SplitExpense/SplitPercentageInput.tsx b/src/components/SelectionListWithSections/SplitExpense/SplitPercentageInput.tsx
index 397e34337c17..6f2ac3efebca 100644
--- a/src/components/SelectionListWithSections/SplitExpense/SplitPercentageInput.tsx
+++ b/src/components/SelectionListWithSections/SplitExpense/SplitPercentageInput.tsx
@@ -60,6 +60,4 @@ function SplitPercentageInput({splitItem, contentWidth, percentageDraft, onSplit
     );
 }
 
-SplitPercentageInput.displayName = 'SplitPercentageInput';
-
 export default SplitPercentageInput;
diff --git a/src/components/SelectionListWithSections/SplitListItemInput.tsx b/src/components/SelectionListWithSections/SplitListItemInput.tsx
index edeb303f2f2a..5eebfe960ca7 100644
--- a/src/components/SelectionListWithSections/SplitListItemInput.tsx
+++ b/src/components/SelectionListWithSections/SplitListItemInput.tsx
@@ -66,6 +66,4 @@ function SplitListItemInput({
     );
 }
 
-SplitListItemInput.displayName = 'SplitListItemInput';
-
 export default SplitListItemInput;

From 1f4746342d910b9e5b2af464c57c22443c148b6a Mon Sep 17 00:00:00 2001
From: Kevin Brian Bader <kevin.bader96@gmail.com>
Date: Sat, 20 Dec 2025 16:41:54 -0800
Subject: [PATCH 3/3] refactoring: merge SplitAmountList and
 SplitPercentageList

---
 src/pages/iou/SplitExpensePage.tsx            | 15 ++--
 .../{SplitAmountList.tsx => SplitList.tsx}    | 27 +++++---
 src/pages/iou/SplitPercentageList.tsx         | 69 -------------------
 3 files changed, 25 insertions(+), 86 deletions(-)
 rename src/pages/iou/{SplitAmountList.tsx => SplitList.tsx} (74%)
 delete mode 100644 src/pages/iou/SplitPercentageList.tsx

diff --git a/src/pages/iou/SplitExpensePage.tsx b/src/pages/iou/SplitExpensePage.tsx
index 16014b39df8b..1302493d36cb 100644
--- a/src/pages/iou/SplitExpensePage.tsx
+++ b/src/pages/iou/SplitExpensePage.tsx
@@ -54,8 +54,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 import type SCREENS from '@src/SCREENS';
 import {isEmptyObject} from '@src/types/utils/EmptyObject';
-import SplitAmountList from './SplitAmountList';
-import SplitPercentageList from './SplitPercentageList';
+import SplitList from './SplitList';
 
 type SplitExpensePageProps = PlatformStackScreenProps<SplitExpenseParamList, typeof SCREENS.MONEY_REQUEST.SPLIT_EXPENSE>;
 
@@ -481,11 +480,12 @@ function SplitExpensePage({route}: SplitExpensePageProps) {
                                     {() => (
                                         <TabScreenWithFocusTrapWrapper>
                                             <View style={styles.flex1}>
-                                                <SplitAmountList
+                                                <SplitList
                                                     sections={sections}
                                                     initiallyFocusedOptionKey={initiallyFocusedOptionKey ?? undefined}
                                                     onSelectRow={onSelectRow}
                                                     listFooterContent={listFooterContent}
+                                                    mode={CONST.TAB.SPLIT.AMOUNT}
                                                 />
                                                 {footerContent}
                                             </View>
@@ -496,11 +496,12 @@ function SplitExpensePage({route}: SplitExpensePageProps) {
                                     {() => (
                                         <TabScreenWithFocusTrapWrapper>
                                             <View style={styles.flex1}>
-                                                <SplitPercentageList
+                                                <SplitList
                                                     sections={sections}
                                                     initiallyFocusedOptionKey={initiallyFocusedOptionKey ?? undefined}
                                                     onSelectRow={onSelectRow}
                                                     listFooterContent={listFooterContent}
+                                                    mode={CONST.TAB.SPLIT.PERCENTAGE}
                                                 />
                                                 {footerContent}
                                             </View>
@@ -512,11 +513,12 @@ function SplitExpensePage({route}: SplitExpensePageProps) {
                                         <TabScreenWithFocusTrapWrapper>
                                             <View style={styles.flex1}>
                                                 {headerDateContent}
-                                                <SplitAmountList
+                                                <SplitList
                                                     sections={sections}
                                                     initiallyFocusedOptionKey={initiallyFocusedOptionKey ?? undefined}
                                                     onSelectRow={onSelectRow}
                                                     listFooterContent={<View style={[shouldUseNarrowLayout && styles.mb3]} />}
+                                                    mode={CONST.TAB.SPLIT.DATE}
                                                 />
                                                 {footerContent}
                                             </View>
@@ -527,11 +529,12 @@ function SplitExpensePage({route}: SplitExpensePageProps) {
                         </View>
                     ) : (
                         <View style={styles.flex1}>
-                            <SplitAmountList
+                            <SplitList
                                 sections={sections}
                                 initiallyFocusedOptionKey={initiallyFocusedOptionKey ?? undefined}
                                 onSelectRow={onSelectRow}
                                 listFooterContent={listFooterContent}
+                                mode={CONST.TAB.SPLIT.AMOUNT}
                             />
                             {footerContent}
                         </View>
diff --git a/src/pages/iou/SplitAmountList.tsx b/src/pages/iou/SplitList.tsx
similarity index 74%
rename from src/pages/iou/SplitAmountList.tsx
rename to src/pages/iou/SplitList.tsx
index d8ccea36f571..6c3393b6f7fa 100644
--- a/src/pages/iou/SplitAmountList.tsx
+++ b/src/pages/iou/SplitList.tsx
@@ -1,5 +1,6 @@
 import React, {useMemo} from 'react';
 import {KeyboardAwareScrollView} from 'react-native-keyboard-controller';
+import type {ValueOf} from 'type-fest';
 // eslint-disable-next-line no-restricted-imports
 import SelectionList from '@components/SelectionListWithSections';
 import type {SectionListDataType, SplitListItemType} from '@components/SelectionListWithSections/types';
@@ -7,7 +8,7 @@ import useDisplayFocusedInputUnderKeyboard from '@hooks/useDisplayFocusedInputUn
 import useThemeStyles from '@hooks/useThemeStyles';
 import CONST from '@src/CONST';
 
-type SplitAmountListProps = {
+type SplitListProps = {
     /** The split expense sections data. */
     sections: Array<SectionListDataType<SplitListItemType>>;
     /** The initially focused option key. */
@@ -16,25 +17,30 @@ type SplitAmountListProps = {
     onSelectRow: (item: SplitListItemType) => void;
     /** Footer content to render at the bottom of the list. */
     listFooterContent?: React.JSX.Element | null;
+    /** The split mode to use (amount, percentage, or date). */
+    mode: ValueOf<typeof CONST.TAB.SPLIT>;
 };
 
 /**
- * Dedicated component for the Amount tab in Split Expense flow.
- * Renders split items with amount inputs, managing its own scroll/height state.
+ * Unified component for split expense tabs (Amount, Percentage, Date).
+ * Renders split items with the appropriate input type based on mode,
+ * managing its own scroll/height state.
  */
-function SplitAmountList({sections, initiallyFocusedOptionKey, onSelectRow, listFooterContent}: SplitAmountListProps) {
+function SplitList({sections, initiallyFocusedOptionKey, onSelectRow, listFooterContent, mode}: SplitListProps) {
     const styles = useThemeStyles();
     const {listRef, bottomOffset, scrollToFocusedInput, SplitListItem} = useDisplayFocusedInputUnderKeyboard();
 
-    const amountSections = useMemo(() => {
+    const splitSections = useMemo(() => {
         return sections.map((section) => ({
             ...section,
             data: section.data.map((item) => ({
                 ...item,
-                mode: CONST.TAB.SPLIT.AMOUNT,
+                mode,
             })),
         }));
-    }, [sections]);
+    }, [sections, mode]);
+
+    const isPercentageMode = mode === CONST.TAB.SPLIT.PERCENTAGE;
 
     return (
         <SelectionList
@@ -48,7 +54,7 @@ function SplitAmountList({sections, initiallyFocusedOptionKey, onSelectRow, list
             )}
             onSelectRow={onSelectRow}
             ref={listRef}
-            sections={amountSections}
+            sections={splitSections}
             initiallyFocusedOptionKey={initiallyFocusedOptionKey}
             ListItem={SplitListItem}
             containerStyle={[styles.flexBasisAuto]}
@@ -59,10 +65,9 @@ function SplitAmountList({sections, initiallyFocusedOptionKey, onSelectRow, list
             shouldPreventDefaultFocusOnSelectRow
             removeClippedSubviews={false}
             shouldHideListOnInitialRender={false}
+            shouldSkipContentHeaderHeightOffset={isPercentageMode}
         />
     );
 }
 
-SplitAmountList.displayName = 'SplitAmountList';
-
-export default SplitAmountList;
+export default SplitList;
diff --git a/src/pages/iou/SplitPercentageList.tsx b/src/pages/iou/SplitPercentageList.tsx
deleted file mode 100644
index 9a3281b2636b..000000000000
--- a/src/pages/iou/SplitPercentageList.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, {useMemo} from 'react';
-import {KeyboardAwareScrollView} from 'react-native-keyboard-controller';
-// eslint-disable-next-line no-restricted-imports
-import SelectionList from '@components/SelectionListWithSections';
-import type {SectionListDataType, SplitListItemType} from '@components/SelectionListWithSections/types';
-import useDisplayFocusedInputUnderKeyboard from '@hooks/useDisplayFocusedInputUnderKeyboard';
-import useThemeStyles from '@hooks/useThemeStyles';
-import CONST from '@src/CONST';
-
-type SplitPercentageListProps = {
-    /** The split expense sections data. */
-    sections: Array<SectionListDataType<SplitListItemType>>;
-    /** The initially focused option key. */
-    initiallyFocusedOptionKey: string | undefined;
-    /** Callback when a row is selected. */
-    onSelectRow: (item: SplitListItemType) => void;
-    /** Footer content to render at the bottom of the list. */
-    listFooterContent?: React.JSX.Element | null;
-};
-
-/**
- * Dedicated component for the Percentage tab in Split Expense flow.
- * Renders split items with percentage inputs, managing its own scroll/height state.
- */
-function SplitPercentageList({sections, initiallyFocusedOptionKey, onSelectRow, listFooterContent}: SplitPercentageListProps) {
-    const styles = useThemeStyles();
-    const {listRef, bottomOffset, scrollToFocusedInput, SplitListItem} = useDisplayFocusedInputUnderKeyboard();
-
-    const percentageSections = useMemo(() => {
-        return sections.map((section) => ({
-            ...section,
-            data: section.data.map((item) => ({
-                ...item,
-                mode: CONST.TAB.SPLIT.PERCENTAGE,
-            })),
-        }));
-    }, [sections]);
-
-    return (
-        <SelectionList
-            renderScrollComponent={(props) => (
-                <KeyboardAwareScrollView
-                    // eslint-disable-next-line react/jsx-props-no-spreading
-                    {...props}
-                    bottomOffset={bottomOffset.current}
-                    onLayout={() => scrollToFocusedInput()}
-                />
-            )}
-            onSelectRow={onSelectRow}
-            ref={listRef}
-            sections={percentageSections}
-            initiallyFocusedOptionKey={initiallyFocusedOptionKey}
-            ListItem={SplitListItem}
-            containerStyle={[styles.flexBasisAuto]}
-            listFooterContent={listFooterContent}
-            disableKeyboardShortcuts
-            shouldSingleExecuteRowSelect
-            canSelectMultiple={false}
-            shouldPreventDefaultFocusOnSelectRow
-            removeClippedSubviews={false}
-            shouldHideListOnInitialRender={false}
-            shouldSkipContentHeaderHeightOffset
-        />
-    );
-}
-
-SplitPercentageList.displayName = 'SplitPercentageList';
-
-export default SplitPercentageList;
