From f843b5f1216e753c7c802e786668e10857f4cc82 Mon Sep 17 00:00:00 2001 From: Yauheni Horbach Date: Thu, 18 Dec 2025 20:23:11 +0100 Subject: [PATCH 1/7] Fix few issues --- .../DatePicker/CalendarPicker/Day.tsx | 41 +++++++++++++++++-- .../DatePicker/CalendarPicker/index.tsx | 21 ++++++---- src/components/DatePicker/DatePickerModal.tsx | 2 + src/components/DatePicker/index.tsx | 5 ++- src/components/DatePicker/types.ts | 6 +++ src/libs/Navigation/OnyxTabNavigator.tsx | 10 ++++- src/libs/actions/Tab.ts | 9 ++-- .../iou/SplitExpenseCreateDateRagePage.tsx | 4 ++ src/pages/iou/SplitExpensePage.tsx | 1 + 9 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/components/DatePicker/CalendarPicker/Day.tsx b/src/components/DatePicker/CalendarPicker/Day.tsx index 3db884bb7fdc0..770ee7a58d78a 100644 --- a/src/components/DatePicker/CalendarPicker/Day.tsx +++ b/src/components/DatePicker/CalendarPicker/Day.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {View} from 'react-native'; import Text from '@components/Text'; import useStyleUtils from '@hooks/useStyleUtils'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import getButtonState from '@libs/getButtonState'; @@ -12,6 +13,12 @@ type DayProps = { /** Whether day is selected */ selected?: boolean; + /** Whether day is the current date (today or initial date) */ + isCurrent?: boolean; + + /** Whether currentDate was provided - changes styling behavior */ + hasCurrentDate?: boolean; + /** Whether day is pressed */ pressed?: boolean; @@ -22,18 +29,44 @@ type DayProps = { children?: number; }; -function Day({disabled, selected, pressed, hovered, children}: DayProps) { +function Day({disabled, selected, isCurrent, hasCurrentDate, pressed, hovered, children}: DayProps) { + const theme = useTheme(); const themeStyles = useThemeStyles(); const StyleUtils = useStyleUtils(); + + const getSelectedStyle = () => { + if (!selected) { + return {}; + } + // If currentDate is provided, selected date gets green circle + if (hasCurrentDate) { + return {backgroundColor: theme.success}; + } + // Default behavior (no currentDate) - selected date gets gray background + return themeStyles.buttonDefaultBG; + }; + + const getCurrentStyle = () => { + // Current date gets gray background (only if not selected) + if (isCurrent && !selected) { + return themeStyles.highlightBG; + } + return {}; + }; + + // Show white text on green background (selected with currentDate) + const shouldShowWhiteText = selected && hasCurrentDate; + return ( - {children} + {children} ); } diff --git a/src/components/DatePicker/CalendarPicker/index.tsx b/src/components/DatePicker/CalendarPicker/index.tsx index b46720c88c829..728a4ca64da4f 100644 --- a/src/components/DatePicker/CalendarPicker/index.tsx +++ b/src/components/DatePicker/CalendarPicker/index.tsx @@ -21,6 +21,9 @@ type CalendarPickerProps = { /** An initial value of date string */ value?: Date | string; + /** Current date to highlight (e.g., today or initial date) */ + currentDate?: Date | string; + /** A minimum date (oldest) allowed to select */ minDate?: Date; @@ -50,7 +53,8 @@ function getInitialCurrentDateView(value: Date | string, minDate: Date, maxDate: } function CalendarPicker({ - value = new Date(), + value, + currentDate, minDate = setYear(new Date(), CONST.CALENDAR_PICKER.MIN_YEAR), maxDate = setYear(new Date(), CONST.CALENDAR_PICKER.MAX_YEAR), onSelected, @@ -63,7 +67,7 @@ function CalendarPicker({ const themeStyles = useThemeStyles(); const {translate} = useLocalize(); const pressableRef = useRef(null); - const [currentDateView, setCurrentDateView] = useState(() => getInitialCurrentDateView(value, minDate, maxDate)); + const [currentDateView, setCurrentDateView] = useState(() => getInitialCurrentDateView(value ?? new Date(), minDate, maxDate)); const [isYearPickerVisible, setIsYearPickerVisible] = useState(false); const isFirstRender = useRef(true); @@ -255,12 +259,13 @@ function CalendarPicker({ style={[themeStyles.flexRow, themeStyles.calendarWeekContainer]} > {week.map((day, index) => { - const currentDate = new Date(currentYearView, currentMonthView, day); - const isBeforeMinDate = currentDate < startOfDay(new Date(minDate)); - const isAfterMaxDate = currentDate > startOfDay(new Date(maxDate)); - const isSelectable = selectableDates ? selectableDates?.some((date) => isSameDay(parseISO(date), currentDate)) : true; + const dayDate = new Date(currentYearView, currentMonthView, day); + const isBeforeMinDate = dayDate < startOfDay(new Date(minDate)); + const isAfterMaxDate = dayDate > startOfDay(new Date(maxDate)); + const isSelectable = selectableDates ? selectableDates?.some((date) => isSameDay(parseISO(date), dayDate)) : true; const isDisabled = !day || isBeforeMinDate || isAfterMaxDate || !isSelectable; - const isSelected = !!day && isSameDay(parseISO(value.toString()), new Date(currentYearView, currentMonthView, day)); + const isSelected = !!day && !!value && isSameDay(typeof value === 'string' ? parseISO(value) : value, new Date(currentYearView, currentMonthView, day)); + const isCurrent = !!day && !!currentDate && isSameDay(typeof currentDate === 'string' ? parseISO(currentDate) : currentDate, new Date(currentYearView, currentMonthView, day)); const handleOnPress = () => { if (!day || isDisabled) { return; @@ -283,6 +288,8 @@ function CalendarPicker({ {({hovered, pressed}) => ( diff --git a/src/components/DatePicker/index.tsx b/src/components/DatePicker/index.tsx index 08f0a75e03ca2..ab38017a32c2d 100644 --- a/src/components/DatePicker/index.tsx +++ b/src/components/DatePicker/index.tsx @@ -17,6 +17,7 @@ const PADDING_MODAL_DATE_PICKER = 8; function DatePicker({ defaultValue, + currentDate, disabled, errorText, inputID, @@ -113,8 +114,7 @@ function DatePicker({ const getValidDateForCalendar = useMemo(() => { if (!selectedDate) { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - return defaultValue || format(new Date(), CONST.DATE.FNS_FORMAT_STRING); + return defaultValue; } return selectedDate; }, [selectedDate, defaultValue]); @@ -153,6 +153,7 @@ function DatePicker({ minDate={minDate} maxDate={maxDate} value={getValidDateForCalendar} + currentDate={currentDate} onSelected={handleDateSelected} isVisible={isModalVisible} onClose={closeDatePicker} diff --git a/src/components/DatePicker/types.ts b/src/components/DatePicker/types.ts index 8f097d608c291..851b2e73a5289 100644 --- a/src/components/DatePicker/types.ts +++ b/src/components/DatePicker/types.ts @@ -17,6 +17,9 @@ type DatePickerBaseProps = ForwardedFSClassProps & { */ defaultValue?: string; + /** Current date to highlight (e.g., today or initial date) */ + currentDate?: string; + inputID: string; /** A minimum date of calendar to select */ @@ -75,6 +78,9 @@ type DatePickerProps = { */ defaultValue?: string; + /** Current date to highlight (e.g., today or initial date) */ + currentDate?: string; + inputID: string; /** A minimum date of calendar to select */ diff --git a/src/libs/Navigation/OnyxTabNavigator.tsx b/src/libs/Navigation/OnyxTabNavigator.tsx index 43a281e83a0b4..7975a5d3d3556 100644 --- a/src/libs/Navigation/OnyxTabNavigator.tsx +++ b/src/libs/Navigation/OnyxTabNavigator.tsx @@ -16,6 +16,8 @@ import type ChildrenProps from '@src/types/utils/ChildrenProps'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import {defaultScreenOptions} from './OnyxTabNavigatorConfig'; +type TabCollectionKey = typeof ONYXKEYS.COLLECTION.SELECTED_TAB | typeof ONYXKEYS.COLLECTION.SPLIT_SELECTED_TAB; + type OnyxTabNavigatorProps = ChildrenProps & { /** ID of the tab component to be saved in onyx */ id: string; @@ -23,6 +25,9 @@ type OnyxTabNavigatorProps = ChildrenProps & { /** Name of the selected tab */ defaultSelectedTab?: SelectedTabRequest | SplitSelectedTabRequest; + /** Onyx collection key to use for storing selected tab. Defaults to SELECTED_TAB */ + collectionKey?: TabCollectionKey; + /** A function triggered when a tab has been selected */ onTabSelected?: (newIouType: IOURequestType) => void; @@ -92,6 +97,7 @@ const getTabNames = (children: React.ReactNode): string[] => { function OnyxTabNavigator({ id, defaultSelectedTab, + collectionKey = ONYXKEYS.COLLECTION.SELECTED_TAB, tabBar: TabBar, children, onTabBarFocusTrapContainerElementChanged, @@ -108,7 +114,7 @@ function OnyxTabNavigator({ }: OnyxTabNavigatorProps) { // Mapping of tab name to focus trap container element const [focusTrapContainerElementMapping, setFocusTrapContainerElementMapping] = useState>({}); - const [selectedTab, selectedTabResult] = useOnyx(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`, {canBeMissing: true}); + const [selectedTab, selectedTabResult] = useOnyx(`${collectionKey}${id}`, {canBeMissing: true}); const tabNames = useMemo(() => getTabNames(children), [children]); @@ -182,7 +188,7 @@ function OnyxTabNavigator({ if (selectedTab === newSelectedTab) { return; } - Tab.setSelectedTab(id, newSelectedTab as SelectedTabRequest); + Tab.setSelectedTab(id, newSelectedTab as SelectedTabRequest | SplitSelectedTabRequest, collectionKey); onTabSelected(newSelectedTab as IOURequestType); }, ...(screenListeners ?? {}), diff --git a/src/libs/actions/Tab.ts b/src/libs/actions/Tab.ts index 109cf590363c1..5f3d6c9497998 100644 --- a/src/libs/actions/Tab.ts +++ b/src/libs/actions/Tab.ts @@ -1,12 +1,15 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {SelectedTabRequest} from '@src/types/onyx'; +import type {OnyxKey} from '@src/ONYXKEYS'; +import type {SelectedTabRequest, SplitSelectedTabRequest} from '@src/types/onyx'; + +type TabCollectionKey = typeof ONYXKEYS.COLLECTION.SELECTED_TAB | typeof ONYXKEYS.COLLECTION.SPLIT_SELECTED_TAB; /** * Sets the selected tab for a given tab ID */ -function setSelectedTab(id: string, index: SelectedTabRequest) { - Onyx.merge(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`, index); +function setSelectedTab(id: string, index: SelectedTabRequest | SplitSelectedTabRequest, collectionKey: TabCollectionKey = ONYXKEYS.COLLECTION.SELECTED_TAB) { + Onyx.merge(`${collectionKey}${id}` as OnyxKey, index); } export default { diff --git a/src/pages/iou/SplitExpenseCreateDateRagePage.tsx b/src/pages/iou/SplitExpenseCreateDateRagePage.tsx index 7cb001e41d9ab..5ae1e93d32297 100644 --- a/src/pages/iou/SplitExpenseCreateDateRagePage.tsx +++ b/src/pages/iou/SplitExpenseCreateDateRagePage.tsx @@ -25,6 +25,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/SplitExpenseEditDateForm'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import DateUtils from '@libs/DateUtils'; type SplitExpenseCreateDateRagePageProps = PlatformStackScreenProps; @@ -32,6 +33,7 @@ function SplitExpenseCreateDateRagePage({route}: SplitExpenseCreateDateRagePageP const styles = useThemeStyles(); const {translate} = useLocalize(); const searchContext = useSearchContext(); + const todayDate = DateUtils.extractDate(new Date().toISOString()); const {reportID, transactionID, backTo} = route.params; @@ -110,6 +112,7 @@ function SplitExpenseCreateDateRagePage({route}: SplitExpenseCreateDateRagePageP maxDate={CONST.CALENDAR_PICKER.MAX_DATE} minDate={CONST.CALENDAR_PICKER.MIN_DATE} defaultValue={draftTransaction?.comment?.splitsStartDate} + currentDate={todayDate} autoFocus /> diff --git a/src/pages/iou/SplitExpensePage.tsx b/src/pages/iou/SplitExpensePage.tsx index a8d5f782c18ad..2157052ed751c 100644 --- a/src/pages/iou/SplitExpensePage.tsx +++ b/src/pages/iou/SplitExpensePage.tsx @@ -475,6 +475,7 @@ function SplitExpensePage({route}: SplitExpensePageProps) { From f24a9f250568a49f73111400632945eee968158e Mon Sep 17 00:00:00 2001 From: Yauheni Horbach Date: Thu, 18 Dec 2025 22:20:00 +0100 Subject: [PATCH 2/7] Fix some issues --- .../DatePicker/CalendarPicker/Day.tsx | 40 ++----------------- .../DatePicker/CalendarPicker/index.tsx | 21 ++++------ src/components/DatePicker/DatePickerModal.tsx | 2 - src/components/DatePicker/index.tsx | 5 +-- src/components/DatePicker/types.ts | 6 --- src/libs/actions/IOU.ts | 4 ++ .../iou/SplitExpenseCreateDateRagePage.tsx | 4 -- src/pages/iou/SplitExpensePage.tsx | 1 + src/pages/workspace/WorkspacesListPage.tsx | 2 +- 9 files changed, 19 insertions(+), 66 deletions(-) diff --git a/src/components/DatePicker/CalendarPicker/Day.tsx b/src/components/DatePicker/CalendarPicker/Day.tsx index 770ee7a58d78a..874720d14dde8 100644 --- a/src/components/DatePicker/CalendarPicker/Day.tsx +++ b/src/components/DatePicker/CalendarPicker/Day.tsx @@ -2,7 +2,6 @@ import React from 'react'; import {View} from 'react-native'; import Text from '@components/Text'; import useStyleUtils from '@hooks/useStyleUtils'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import getButtonState from '@libs/getButtonState'; @@ -13,12 +12,6 @@ type DayProps = { /** Whether day is selected */ selected?: boolean; - /** Whether day is the current date (today or initial date) */ - isCurrent?: boolean; - - /** Whether currentDate was provided - changes styling behavior */ - hasCurrentDate?: boolean; - /** Whether day is pressed */ pressed?: boolean; @@ -29,44 +22,19 @@ type DayProps = { children?: number; }; -function Day({disabled, selected, isCurrent, hasCurrentDate, pressed, hovered, children}: DayProps) { - const theme = useTheme(); +function Day({disabled, selected, pressed, hovered, children}: DayProps) { const themeStyles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const getSelectedStyle = () => { - if (!selected) { - return {}; - } - // If currentDate is provided, selected date gets green circle - if (hasCurrentDate) { - return {backgroundColor: theme.success}; - } - // Default behavior (no currentDate) - selected date gets gray background - return themeStyles.buttonDefaultBG; - }; - - const getCurrentStyle = () => { - // Current date gets gray background (only if not selected) - if (isCurrent && !selected) { - return themeStyles.highlightBG; - } - return {}; - }; - - // Show white text on green background (selected with currentDate) - const shouldShowWhiteText = selected && hasCurrentDate; - return ( - {children} + {children} ); } diff --git a/src/components/DatePicker/CalendarPicker/index.tsx b/src/components/DatePicker/CalendarPicker/index.tsx index 728a4ca64da4f..b46720c88c829 100644 --- a/src/components/DatePicker/CalendarPicker/index.tsx +++ b/src/components/DatePicker/CalendarPicker/index.tsx @@ -21,9 +21,6 @@ type CalendarPickerProps = { /** An initial value of date string */ value?: Date | string; - /** Current date to highlight (e.g., today or initial date) */ - currentDate?: Date | string; - /** A minimum date (oldest) allowed to select */ minDate?: Date; @@ -53,8 +50,7 @@ function getInitialCurrentDateView(value: Date | string, minDate: Date, maxDate: } function CalendarPicker({ - value, - currentDate, + value = new Date(), minDate = setYear(new Date(), CONST.CALENDAR_PICKER.MIN_YEAR), maxDate = setYear(new Date(), CONST.CALENDAR_PICKER.MAX_YEAR), onSelected, @@ -67,7 +63,7 @@ function CalendarPicker({ const themeStyles = useThemeStyles(); const {translate} = useLocalize(); const pressableRef = useRef(null); - const [currentDateView, setCurrentDateView] = useState(() => getInitialCurrentDateView(value ?? new Date(), minDate, maxDate)); + const [currentDateView, setCurrentDateView] = useState(() => getInitialCurrentDateView(value, minDate, maxDate)); const [isYearPickerVisible, setIsYearPickerVisible] = useState(false); const isFirstRender = useRef(true); @@ -259,13 +255,12 @@ function CalendarPicker({ style={[themeStyles.flexRow, themeStyles.calendarWeekContainer]} > {week.map((day, index) => { - const dayDate = new Date(currentYearView, currentMonthView, day); - const isBeforeMinDate = dayDate < startOfDay(new Date(minDate)); - const isAfterMaxDate = dayDate > startOfDay(new Date(maxDate)); - const isSelectable = selectableDates ? selectableDates?.some((date) => isSameDay(parseISO(date), dayDate)) : true; + const currentDate = new Date(currentYearView, currentMonthView, day); + const isBeforeMinDate = currentDate < startOfDay(new Date(minDate)); + const isAfterMaxDate = currentDate > startOfDay(new Date(maxDate)); + const isSelectable = selectableDates ? selectableDates?.some((date) => isSameDay(parseISO(date), currentDate)) : true; const isDisabled = !day || isBeforeMinDate || isAfterMaxDate || !isSelectable; - const isSelected = !!day && !!value && isSameDay(typeof value === 'string' ? parseISO(value) : value, new Date(currentYearView, currentMonthView, day)); - const isCurrent = !!day && !!currentDate && isSameDay(typeof currentDate === 'string' ? parseISO(currentDate) : currentDate, new Date(currentYearView, currentMonthView, day)); + const isSelected = !!day && isSameDay(parseISO(value.toString()), new Date(currentYearView, currentMonthView, day)); const handleOnPress = () => { if (!day || isDisabled) { return; @@ -288,8 +283,6 @@ function CalendarPicker({ {({hovered, pressed}) => ( diff --git a/src/components/DatePicker/index.tsx b/src/components/DatePicker/index.tsx index ab38017a32c2d..732c4276e5e60 100644 --- a/src/components/DatePicker/index.tsx +++ b/src/components/DatePicker/index.tsx @@ -17,7 +17,6 @@ const PADDING_MODAL_DATE_PICKER = 8; function DatePicker({ defaultValue, - currentDate, disabled, errorText, inputID, @@ -116,7 +115,8 @@ function DatePicker({ if (!selectedDate) { return defaultValue; } - return selectedDate; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + return defaultValue || format(new Date(), CONST.DATE.FNS_FORMAT_STRING); }, [selectedDate, defaultValue]); return ( @@ -153,7 +153,6 @@ function DatePicker({ minDate={minDate} maxDate={maxDate} value={getValidDateForCalendar} - currentDate={currentDate} onSelected={handleDateSelected} isVisible={isModalVisible} onClose={closeDatePicker} diff --git a/src/components/DatePicker/types.ts b/src/components/DatePicker/types.ts index 851b2e73a5289..8f097d608c291 100644 --- a/src/components/DatePicker/types.ts +++ b/src/components/DatePicker/types.ts @@ -17,9 +17,6 @@ type DatePickerBaseProps = ForwardedFSClassProps & { */ defaultValue?: string; - /** Current date to highlight (e.g., today or initial date) */ - currentDate?: string; - inputID: string; /** A minimum date of calendar to select */ @@ -78,9 +75,6 @@ type DatePickerProps = { */ defaultValue?: string; - /** Current date to highlight (e.g., today or initial date) */ - currentDate?: string; - inputID: string; /** A minimum date of calendar to select */ diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f801571c4f0f0..31c76b585cf2f 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -14516,6 +14516,8 @@ function addSplitExpenseField(transaction: OnyxEntry, dra reportID: draftTransaction?.reportID, }), ], + splitsStartDate: null, + splitsEndDate: null, }, }); } @@ -14616,6 +14618,8 @@ function removeSplitExpenseField(draftTransaction: OnyxEntry; @@ -33,7 +32,6 @@ function SplitExpenseCreateDateRagePage({route}: SplitExpenseCreateDateRagePageP const styles = useThemeStyles(); const {translate} = useLocalize(); const searchContext = useSearchContext(); - const todayDate = DateUtils.extractDate(new Date().toISOString()); const {reportID, transactionID, backTo} = route.params; @@ -112,7 +110,6 @@ function SplitExpenseCreateDateRagePage({route}: SplitExpenseCreateDateRagePageP maxDate={CONST.CALENDAR_PICKER.MAX_DATE} minDate={CONST.CALENDAR_PICKER.MIN_DATE} defaultValue={draftTransaction?.comment?.splitsStartDate} - currentDate={todayDate} autoFocus /> diff --git a/src/pages/iou/SplitExpensePage.tsx b/src/pages/iou/SplitExpensePage.tsx index 2157052ed751c..3b7bd61eaf701 100644 --- a/src/pages/iou/SplitExpensePage.tsx +++ b/src/pages/iou/SplitExpensePage.tsx @@ -517,6 +517,7 @@ function SplitExpensePage({route}: SplitExpensePageProps) { sections={sections} initiallyFocusedOptionKey={initiallyFocusedOptionKey ?? undefined} onSelectRow={onSelectRow} + listFooterContent={} /> {footerContent} diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 7521e100232cd..c4c693650d199 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -585,7 +585,7 @@ function WorkspacesListPage() { } return Object.values(allDomains).reduce((domainItems, domain) => { - if (!domain) { + if (!domain || !domain?.email) { return domainItems; } From 0ad761d08e0b166c40d34b3abc624b345aebfa6a Mon Sep 17 00:00:00 2001 From: Yauheni Horbach Date: Thu, 18 Dec 2025 22:21:46 +0100 Subject: [PATCH 3/7] Revert some changes --- src/components/DatePicker/CalendarPicker/Day.tsx | 1 - src/components/DatePicker/index.tsx | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/DatePicker/CalendarPicker/Day.tsx b/src/components/DatePicker/CalendarPicker/Day.tsx index 874720d14dde8..3db884bb7fdc0 100644 --- a/src/components/DatePicker/CalendarPicker/Day.tsx +++ b/src/components/DatePicker/CalendarPicker/Day.tsx @@ -25,7 +25,6 @@ type DayProps = { function Day({disabled, selected, pressed, hovered, children}: DayProps) { const themeStyles = useThemeStyles(); const StyleUtils = useStyleUtils(); - return ( { if (!selectedDate) { - return defaultValue; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + return defaultValue || format(new Date(), CONST.DATE.FNS_FORMAT_STRING); } - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - return defaultValue || format(new Date(), CONST.DATE.FNS_FORMAT_STRING); + return selectedDate; }, [selectedDate, defaultValue]); return ( From 911f8178501eba63846d0083a71cd204b9f40403 Mon Sep 17 00:00:00 2001 From: Yauheni Horbach Date: Fri, 19 Dec 2025 13:02:47 +0100 Subject: [PATCH 4/7] Update route for spli_create_date_range --- src/ROUTES.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 964a287fa1a0a..85dd5fc76e760 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -759,7 +759,7 @@ const ROUTES = { }, }, SPLIT_EXPENSE_CREATE_DATE_RANGE: { - route: 'create/split-expense/create-date-range/:reportID/:transactionID/:splitExpenseTransactionID?', + route: 'create/split-expense/create-date-range/:reportID/:transactionID?', getRoute: (reportID: string | undefined, transactionID: string | undefined, backTo?: string) => { if (!reportID || !transactionID) { Log.warn(`Invalid ${reportID}(reportID) or ${transactionID}(transactionID) is used to build the SPLIT_EXPENSE_CREATE_DATE_RANGE route`); From 1449c7d6c382989ceda98217ca07f7b4a29894fd Mon Sep 17 00:00:00 2001 From: Yauheni Horbach Date: Fri, 19 Dec 2025 16:13:33 +0100 Subject: [PATCH 5/7] Fix issue with double navigation --- src/ROUTES.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 85dd5fc76e760..67b77180cf405 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -748,14 +748,16 @@ const ROUTES = { }, }, SPLIT_EXPENSE: { - route: 'create/split-expense/overview/:reportID/:transactionID/:splitExpenseTransactionID?', + route: 'create/split-expense/overview/:reportID/:transactionID/:splitExpenseTransactionID/:backTo?', getRoute: (reportID: string | undefined, originalTransactionID: string | undefined, splitExpenseTransactionID?: string, backTo?: string) => { if (!reportID || !originalTransactionID) { Log.warn(`Invalid ${reportID}(reportID) or ${originalTransactionID}(transactionID) is used to build the SPLIT_EXPENSE route`); } + const splitExpenseTransactionIDPart = splitExpenseTransactionID ? `/${splitExpenseTransactionID}` : '/0'; + // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - return getUrlWithBackToParam(`create/split-expense/overview/${reportID}/${originalTransactionID}${splitExpenseTransactionID ? `/${splitExpenseTransactionID}` : ''}`, backTo); + return getUrlWithBackToParam(`create/split-expense/overview/${reportID}/${originalTransactionID}${splitExpenseTransactionIDPart}`, backTo); }, }, SPLIT_EXPENSE_CREATE_DATE_RANGE: { From ff38fc606a47839a1a5a8bd7733e087dc5a1a912 Mon Sep 17 00:00:00 2001 From: Yauheni Horbach Date: Fri, 19 Dec 2025 18:22:43 +0100 Subject: [PATCH 6/7] Remove SPLIT_SELECTED_TAB --- src/CONST/index.ts | 10 ++++---- src/ONYXKEYS.ts | 4 ---- src/ROUTES.ts | 1 + .../SplitListItem.tsx | 2 +- .../SelectionListWithSections/types.ts | 4 ++-- src/components/TabSelector/TabSelector.tsx | 6 ++--- src/libs/Navigation/OnyxTabNavigator.tsx | 14 ++++------- src/libs/Navigation/linkingConfig/config.ts | 12 +++++----- src/libs/actions/Tab.ts | 9 +++----- src/pages/iou/SplitAmountList.tsx | 2 +- src/pages/iou/SplitExpensePage.tsx | 23 +++++++++---------- src/pages/iou/SplitPercentageList.tsx | 2 +- src/types/onyx/SelectedTabRequest.ts | 2 +- src/types/onyx/SplitSelectedTabRequest.ts | 7 ------ src/types/onyx/index.ts | 2 -- 15 files changed, 39 insertions(+), 61 deletions(-) delete mode 100644 src/types/onyx/SplitSelectedTabRequest.ts diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 77cd66f787697..6e40150047de8 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -2938,11 +2938,6 @@ const CONST = { APPROVE: 'approve', TRACK: 'track', }, - SPLIT_TYPE: { - AMOUNT: 'amount', - PERCENTAGE: 'percentage', - DATE: 'date', - }, AMOUNT_MAX_LENGTH: 8, DISTANCE_REQUEST_AMOUNT_MAX_LENGTH: 14, RECEIPT_STATE: { @@ -5476,6 +5471,11 @@ const CONST = { IOU_REQUEST_TYPE: 'iouRequestType', DISTANCE_REQUEST_TYPE: 'distanceRequestType', SPLIT_EXPENSE_TAB_TYPE: 'splitExpenseTabType', + SPLIT: { + AMOUNT: 'amount', + PERCENTAGE: 'percentage', + DATE: 'date', + }, SHARE: { NAVIGATOR_ID: 'ShareNavigatorID', SHARE: 'ShareTab', diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 2474f521872c3..cd6ee05a69d08 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -687,9 +687,6 @@ const ONYXKEYS = { // Manual expense tab selector SELECTED_DISTANCE_REQUEST_TAB: 'selectedDistanceRequestTab_', - // IOU request split tab selector - SPLIT_SELECTED_TAB: 'splitSelectedTab_', - /** This is deprecated, but needed for a migration, so we still need to include it here so that it will be initialized in Onyx.init */ DEPRECATED_POLICY_MEMBER_LIST: 'policyMemberList_', @@ -1121,7 +1118,6 @@ type OnyxCollectionValuesMapping = { [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: OnyxTypes.SelectedTabRequest; [ONYXKEYS.COLLECTION.SELECTED_DISTANCE_REQUEST_TAB]: OnyxTypes.SelectedTabRequest; - [ONYXKEYS.COLLECTION.SPLIT_SELECTED_TAB]: OnyxTypes.SplitSelectedTabRequest; [ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string; [ONYXKEYS.COLLECTION.NVP_EXPENSIFY_REPORT_PDF_FILENAME]: string; [ONYXKEYS.COLLECTION.NEXT_STEP]: OnyxTypes.ReportNextStepDeprecated; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 67b77180cf405..b40b6f32ac23e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -748,6 +748,7 @@ const ROUTES = { }, }, SPLIT_EXPENSE: { + // TODO: Remove backTo from route once we have find another way to fix navigation issues with tabs route: 'create/split-expense/overview/:reportID/:transactionID/:splitExpenseTransactionID/:backTo?', getRoute: (reportID: string | undefined, originalTransactionID: string | undefined, splitExpenseTransactionID?: string, backTo?: string) => { if (!reportID || !originalTransactionID) { diff --git a/src/components/SelectionListWithSections/SplitListItem.tsx b/src/components/SelectionListWithSections/SplitListItem.tsx index a296d5b9f0eee..52353aebacdc1 100644 --- a/src/components/SelectionListWithSections/SplitListItem.tsx +++ b/src/components/SelectionListWithSections/SplitListItem.tsx @@ -82,7 +82,7 @@ function SplitListItem({ inputRef.current = ref; }; - const isPercentageMode = splitItem.mode === CONST.IOU.SPLIT_TYPE.PERCENTAGE; + const isPercentageMode = splitItem.mode === CONST.TAB.SPLIT.PERCENTAGE; return ( ; + mode: ValueOf; /** Percentage value to show when in percentage mode (0-100) */ percentage: number; @@ -604,7 +604,7 @@ type SplitListItemType = ListItem & /** * Function for updating value (amount or percentage based on mode) */ - onSplitExpenseValueChange: (transactionID: string, value: number, mode: ValueOf) => void; + onSplitExpenseValueChange: (transactionID: string, value: number, mode: ValueOf) => void; }; type SplitListItemProps = ListItemProps; diff --git a/src/components/TabSelector/TabSelector.tsx b/src/components/TabSelector/TabSelector.tsx index c23b711f669ea..53364fafb1e33 100644 --- a/src/components/TabSelector/TabSelector.tsx +++ b/src/components/TabSelector/TabSelector.tsx @@ -73,11 +73,11 @@ function getIconTitleAndTestID( return {icon: icons.Pencil, title: translate('tabSelector.manual'), testID: 'distanceManual'}; case CONST.TAB_REQUEST.DISTANCE_GPS: return {icon: icons.Crosshair, title: translate('tabSelector.gps'), testID: 'distanceGPS'}; - case CONST.IOU.SPLIT_TYPE.AMOUNT: + case CONST.TAB.SPLIT.AMOUNT: return {icon: icons.MoneyCircle, title: translate('iou.amount'), testID: 'split-amount'}; - case CONST.IOU.SPLIT_TYPE.PERCENTAGE: + case CONST.TAB.SPLIT.PERCENTAGE: return {icon: icons.Percent, title: translate('iou.percent'), testID: 'split-percentage'}; - case CONST.IOU.SPLIT_TYPE.DATE: + case CONST.TAB.SPLIT.DATE: return {icon: icons.CalendarSolid, title: translate('iou.date'), testID: 'split-date'}; default: throw new Error(`Route ${route} has no icon nor title set.`); diff --git a/src/libs/Navigation/OnyxTabNavigator.tsx b/src/libs/Navigation/OnyxTabNavigator.tsx index 7975a5d3d3556..a7239b76774bf 100644 --- a/src/libs/Navigation/OnyxTabNavigator.tsx +++ b/src/libs/Navigation/OnyxTabNavigator.tsx @@ -11,22 +11,17 @@ import useThemeStyles from '@hooks/useThemeStyles'; import type {IOURequestType} from '@libs/actions/IOU'; import Tab from '@userActions/Tab'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {SelectedTabRequest, SplitSelectedTabRequest} from '@src/types/onyx'; +import type {SelectedTabRequest} from '@src/types/onyx'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import {defaultScreenOptions} from './OnyxTabNavigatorConfig'; -type TabCollectionKey = typeof ONYXKEYS.COLLECTION.SELECTED_TAB | typeof ONYXKEYS.COLLECTION.SPLIT_SELECTED_TAB; - type OnyxTabNavigatorProps = ChildrenProps & { /** ID of the tab component to be saved in onyx */ id: string; /** Name of the selected tab */ - defaultSelectedTab?: SelectedTabRequest | SplitSelectedTabRequest; - - /** Onyx collection key to use for storing selected tab. Defaults to SELECTED_TAB */ - collectionKey?: TabCollectionKey; + defaultSelectedTab?: SelectedTabRequest; /** A function triggered when a tab has been selected */ onTabSelected?: (newIouType: IOURequestType) => void; @@ -97,7 +92,6 @@ const getTabNames = (children: React.ReactNode): string[] => { function OnyxTabNavigator({ id, defaultSelectedTab, - collectionKey = ONYXKEYS.COLLECTION.SELECTED_TAB, tabBar: TabBar, children, onTabBarFocusTrapContainerElementChanged, @@ -114,7 +108,7 @@ function OnyxTabNavigator({ }: OnyxTabNavigatorProps) { // Mapping of tab name to focus trap container element const [focusTrapContainerElementMapping, setFocusTrapContainerElementMapping] = useState>({}); - const [selectedTab, selectedTabResult] = useOnyx(`${collectionKey}${id}`, {canBeMissing: true}); + const [selectedTab, selectedTabResult] = useOnyx(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`, {canBeMissing: true}); const tabNames = useMemo(() => getTabNames(children), [children]); @@ -188,7 +182,7 @@ function OnyxTabNavigator({ if (selectedTab === newSelectedTab) { return; } - Tab.setSelectedTab(id, newSelectedTab as SelectedTabRequest | SplitSelectedTabRequest, collectionKey); + Tab.setSelectedTab(id, newSelectedTab as SelectedTabRequest); onTabSelected(newSelectedTab as IOURequestType); }, ...(screenListeners ?? {}), diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 699cd8b36fe01..a296a17d77fef 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1478,14 +1478,14 @@ const config: LinkingOptions['config'] = { path: ROUTES.SPLIT_EXPENSE.route, exact: true, screens: { - [CONST.IOU.SPLIT_TYPE.AMOUNT]: { - path: CONST.IOU.SPLIT_TYPE.AMOUNT, + [CONST.TAB.SPLIT.AMOUNT]: { + path: CONST.TAB.SPLIT.AMOUNT, }, - [CONST.IOU.SPLIT_TYPE.PERCENTAGE]: { - path: CONST.IOU.SPLIT_TYPE.PERCENTAGE, + [CONST.TAB.SPLIT.PERCENTAGE]: { + path: CONST.TAB.SPLIT.PERCENTAGE, }, - [CONST.IOU.SPLIT_TYPE.DATE]: { - path: CONST.IOU.SPLIT_TYPE.DATE, + [CONST.TAB.SPLIT.DATE]: { + path: CONST.TAB.SPLIT.DATE, }, }, }, diff --git a/src/libs/actions/Tab.ts b/src/libs/actions/Tab.ts index 5f3d6c9497998..109cf590363c1 100644 --- a/src/libs/actions/Tab.ts +++ b/src/libs/actions/Tab.ts @@ -1,15 +1,12 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {OnyxKey} from '@src/ONYXKEYS'; -import type {SelectedTabRequest, SplitSelectedTabRequest} from '@src/types/onyx'; - -type TabCollectionKey = typeof ONYXKEYS.COLLECTION.SELECTED_TAB | typeof ONYXKEYS.COLLECTION.SPLIT_SELECTED_TAB; +import type {SelectedTabRequest} from '@src/types/onyx'; /** * Sets the selected tab for a given tab ID */ -function setSelectedTab(id: string, index: SelectedTabRequest | SplitSelectedTabRequest, collectionKey: TabCollectionKey = ONYXKEYS.COLLECTION.SELECTED_TAB) { - Onyx.merge(`${collectionKey}${id}` as OnyxKey, index); +function setSelectedTab(id: string, index: SelectedTabRequest) { + Onyx.merge(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`, index); } export default { diff --git a/src/pages/iou/SplitAmountList.tsx b/src/pages/iou/SplitAmountList.tsx index ead378fae0dc0..d8ccea36f5713 100644 --- a/src/pages/iou/SplitAmountList.tsx +++ b/src/pages/iou/SplitAmountList.tsx @@ -31,7 +31,7 @@ function SplitAmountList({sections, initiallyFocusedOptionKey, onSelectRow, list ...section, data: section.data.map((item) => ({ ...item, - mode: CONST.IOU.SPLIT_TYPE.AMOUNT, + mode: CONST.TAB.SPLIT.AMOUNT, })), })); }, [sections]); diff --git a/src/pages/iou/SplitExpensePage.tsx b/src/pages/iou/SplitExpensePage.tsx index 70ab034eb9a10..8a377b625fe20 100644 --- a/src/pages/iou/SplitExpensePage.tsx +++ b/src/pages/iou/SplitExpensePage.tsx @@ -71,7 +71,7 @@ function SplitExpensePage({route}: SplitExpensePageProps) { const searchContext = useSearchContext(); - const [selectedTab] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_SELECTED_TAB}${CONST.TAB.SPLIT_EXPENSE_TAB_TYPE}`, {canBeMissing: true}); + const [selectedTab] = useOnyx(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.SPLIT_EXPENSE_TAB_TYPE}`, {canBeMissing: true}); const [draftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: false}); const transactionReport = getReportOrDraftReport(draftTransaction?.reportID); const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); @@ -111,8 +111,8 @@ function SplitExpensePage({route}: SplitExpensePageProps) { const iouActions = getIOUActionForTransactions([originalTransactionID], expenseReport?.reportID); const {iouReport} = useGetIOUReportFromReportAction(iouActions.at(0)); - const isPercentageMode = selectedTab === CONST.IOU.SPLIT_TYPE.PERCENTAGE; - const isDateMode = selectedTab === CONST.IOU.SPLIT_TYPE.DATE; + const isPercentageMode = (selectedTab as string) === CONST.TAB.SPLIT.PERCENTAGE; + const isDateMode = (selectedTab as string) === CONST.TAB.SPLIT.DATE; const childTransactions = useMemo(() => getChildTransactions(allTransactions, allReports, transactionID), [allReports, allTransactions, transactionID]); const splitFieldDataFromChildTransactions = useMemo(() => childTransactions.map((currentTransaction) => initSplitExpenseItemData(currentTransaction)), [childTransactions]); const splitFieldDataFromOriginalTransaction = useMemo(() => initSplitExpenseItemData(transaction), [transaction]); @@ -242,8 +242,8 @@ function SplitExpensePage({route}: SplitExpensePageProps) { ]); const onSplitExpenseValueChange = useCallback( - (id: string, value: number, mode: ValueOf) => { - if (mode === CONST.IOU.SPLIT_TYPE.AMOUNT || mode === CONST.IOU.SPLIT_TYPE.DATE) { + (id: string, value: number, mode: ValueOf) => { + if (mode === CONST.TAB.SPLIT.AMOUNT || mode === CONST.TAB.SPLIT.DATE) { const amountInCents = convertToBackendAmount(value); updateSplitExpenseAmountField(draftTransaction, id, amountInCents); } else { @@ -301,7 +301,7 @@ function SplitExpensePage({route}: SplitExpensePageProps) { currency: draftTransaction?.currency ?? CONST.CURRENCY.USD, transactionID: item?.transactionID ?? CONST.IOU.OPTIMISTIC_TRANSACTION_ID, currencySymbol, - mode: CONST.IOU.SPLIT_TYPE.AMOUNT, + mode: CONST.TAB.SPLIT.AMOUNT, percentage, onSplitExpenseValueChange, isSelected: splitExpenseTransactionID === item.transactionID, @@ -436,7 +436,7 @@ function SplitExpensePage({route}: SplitExpensePageProps) { ); const headerTitle = useMemo(() => { - if (splitExpenseTransactionID) { + if (Number(splitExpenseTransactionID)) { return translate('iou.editSplits'); } if (isPercentageMode) { @@ -485,11 +485,10 @@ function SplitExpensePage({route}: SplitExpensePageProps) { - + {() => ( @@ -504,7 +503,7 @@ function SplitExpensePage({route}: SplitExpensePageProps) { )} - + {() => ( @@ -519,7 +518,7 @@ function SplitExpensePage({route}: SplitExpensePageProps) { )} - + {() => ( diff --git a/src/pages/iou/SplitPercentageList.tsx b/src/pages/iou/SplitPercentageList.tsx index edc5514a37b9a..af796b288ed03 100644 --- a/src/pages/iou/SplitPercentageList.tsx +++ b/src/pages/iou/SplitPercentageList.tsx @@ -31,7 +31,7 @@ function SplitPercentageList({sections, initiallyFocusedOptionKey, onSelectRow, ...section, data: section.data.map((item) => ({ ...item, - mode: CONST.IOU.SPLIT_TYPE.PERCENTAGE, + mode: CONST.TAB.SPLIT.PERCENTAGE, })), })); }, [sections]); diff --git a/src/types/onyx/SelectedTabRequest.ts b/src/types/onyx/SelectedTabRequest.ts index db79b948dcde1..5c4fc6f99066b 100644 --- a/src/types/onyx/SelectedTabRequest.ts +++ b/src/types/onyx/SelectedTabRequest.ts @@ -2,6 +2,6 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; /** Selectable IOU request tabs */ -type SelectedTabRequest = ValueOf; +type SelectedTabRequest = ValueOf | ValueOf; export default SelectedTabRequest; diff --git a/src/types/onyx/SplitSelectedTabRequest.ts b/src/types/onyx/SplitSelectedTabRequest.ts deleted file mode 100644 index b4166d63dadb7..0000000000000 --- a/src/types/onyx/SplitSelectedTabRequest.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type {ValueOf} from 'type-fest'; -import type CONST from '@src/CONST'; - -/** Selectable IOU request split tabs */ -type SplitSelectedTabRequest = ValueOf; - -export default SplitSelectedTabRequest; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 2dab239af2f68..75de16dffe7c6 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -115,7 +115,6 @@ import type SelectedTabRequest from './SelectedTabRequest'; import type Session from './Session'; import type ShareTempFile from './ShareTempFile'; import type SidePanel from './SidePanel'; -import type SplitSelectedTabRequest from './SplitSelectedTabRequest'; import type StripeCustomerID from './StripeCustomerID'; import type SupportalPermissionDenied from './SupportalPermissionDenied'; import type Task from './Task'; @@ -230,7 +229,6 @@ export type { ScreenShareRequest, SecurityGroup, SelectedTabRequest, - SplitSelectedTabRequest, Session, Task, TaxRate, From 751b5f624d3662b019864924ae455a511a756c06 Mon Sep 17 00:00:00 2001 From: Yauheni Horbach Date: Fri, 19 Dec 2025 19:01:05 +0100 Subject: [PATCH 7/7] Fix ts issues --- src/libs/Navigation/OnyxTabNavigator.tsx | 17 +++++++++-------- src/libs/actions/Tab.ts | 5 +++-- src/types/onyx/SelectedTabRequest.ts | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/libs/Navigation/OnyxTabNavigator.tsx b/src/libs/Navigation/OnyxTabNavigator.tsx index a7239b76774bf..0181a0a46f740 100644 --- a/src/libs/Navigation/OnyxTabNavigator.tsx +++ b/src/libs/Navigation/OnyxTabNavigator.tsx @@ -8,7 +8,6 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import type {TabSelectorProps} from '@components/TabSelector/TabSelector'; import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {IOURequestType} from '@libs/actions/IOU'; import Tab from '@userActions/Tab'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SelectedTabRequest} from '@src/types/onyx'; @@ -16,15 +15,15 @@ import type ChildrenProps from '@src/types/utils/ChildrenProps'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import {defaultScreenOptions} from './OnyxTabNavigatorConfig'; -type OnyxTabNavigatorProps = ChildrenProps & { +type OnyxTabNavigatorProps = ChildrenProps & { /** ID of the tab component to be saved in onyx */ id: string; /** Name of the selected tab */ - defaultSelectedTab?: SelectedTabRequest; + defaultSelectedTab?: TTabName; /** A function triggered when a tab has been selected */ - onTabSelected?: (newIouType: IOURequestType) => void; + onTabSelected?: (newTabName: TTabName) => void; tabBar: (props: TabSelectorProps) => React.ReactNode; @@ -89,7 +88,7 @@ const getTabNames = (children: React.ReactNode): string[] => { // This takes all the same props as MaterialTopTabsNavigator: https://reactnavigation.org/docs/material-top-tab-navigator/#props, // except ID is now required, and it gets a `selectedTab` from Onyx // It also takes 2 more optional callbacks to manage the focus trap container elements of the tab bar and the active tab -function OnyxTabNavigator({ +function OnyxTabNavigator({ id, defaultSelectedTab, tabBar: TabBar, @@ -105,7 +104,7 @@ function OnyxTabNavigator({ onTabSelect, equalWidth = false, ...rest -}: OnyxTabNavigatorProps) { +}: OnyxTabNavigatorProps) { // Mapping of tab name to focus trap container element const [focusTrapContainerElementMapping, setFocusTrapContainerElementMapping] = useState>({}); const [selectedTab, selectedTabResult] = useOnyx(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`, {canBeMissing: true}); @@ -182,8 +181,10 @@ function OnyxTabNavigator({ if (selectedTab === newSelectedTab) { return; } - Tab.setSelectedTab(id, newSelectedTab as SelectedTabRequest); - onTabSelected(newSelectedTab as IOURequestType); + if (newSelectedTab) { + Tab.setSelectedTab(id, newSelectedTab as TTabName); + } + onTabSelected(newSelectedTab as TTabName); }, ...(screenListeners ?? {}), }} diff --git a/src/libs/actions/Tab.ts b/src/libs/actions/Tab.ts index 109cf590363c1..dd45435bb71fd 100644 --- a/src/libs/actions/Tab.ts +++ b/src/libs/actions/Tab.ts @@ -1,12 +1,13 @@ import Onyx from 'react-native-onyx'; +import type {OnyxMergeInput} from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SelectedTabRequest} from '@src/types/onyx'; /** * Sets the selected tab for a given tab ID */ -function setSelectedTab(id: string, index: SelectedTabRequest) { - Onyx.merge(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`, index); +function setSelectedTab(id: string, index: TTabName) { + Onyx.merge(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`, index as OnyxMergeInput<`${typeof ONYXKEYS.COLLECTION.SELECTED_TAB}${string}`>); } export default { diff --git a/src/types/onyx/SelectedTabRequest.ts b/src/types/onyx/SelectedTabRequest.ts index 5c4fc6f99066b..db79b948dcde1 100644 --- a/src/types/onyx/SelectedTabRequest.ts +++ b/src/types/onyx/SelectedTabRequest.ts @@ -2,6 +2,6 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; /** Selectable IOU request tabs */ -type SelectedTabRequest = ValueOf | ValueOf; +type SelectedTabRequest = ValueOf; export default SelectedTabRequest;