Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1af8655
feat: date range filter UI and year picker fix (#81501)
btkcodedev Mar 13, 2026
b81c113
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Mar 15, 2026
38bf708
fix Android view collapse and calendar selecting style issue
btkcodedev Mar 15, 2026
66ac605
fix: year selection autoselect on android
btkcodedev Mar 15, 2026
81ae58c
prettify
btkcodedev Mar 15, 2026
237f56a
increase code coverage, utc time fix
btkcodedev Mar 16, 2026
8fcd18d
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Mar 16, 2026
bb90c1b
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Mar 18, 2026
b57910a
fix: yearpickermodal
btkcodedev Mar 18, 2026
f3af178
fix: Advanced filter reset
btkcodedev Mar 18, 2026
d854556
fix: Use single source of SearchDateValues type
btkcodedev Mar 19, 2026
31921ca
prettify
btkcodedev Mar 19, 2026
ebb6b78
fix: polish translation, test fix
btkcodedev Mar 19, 2026
f260778
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Mar 22, 2026
a460410
fix: advanced filter date reset and sub page navigation
btkcodedev Mar 23, 2026
3340968
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Mar 24, 2026
a583502
fix: back to previous state if date is not selected
btkcodedev Mar 24, 2026
44f6975
fix: remove suggested files
btkcodedev Mar 27, 2026
b1cd093
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Mar 27, 2026
ec9cf5e
fix: pass range value to makeDateFilterItem in useSearchActionsBar
btkcodedev Mar 27, 2026
360401e
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Mar 27, 2026
4bfe962
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Mar 29, 2026
2abd500
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Apr 1, 2026
a02f4a0
remove unwated prop
btkcodedev Apr 1, 2026
5495b77
split dateselectpopup into multiple files
btkcodedev Apr 1, 2026
e7821fd
Merge branch 'main' into btkcodedev/81501RangeUI-V2
btkcodedev Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ const CONST = {
POPOVER_MENU_MAX_HEIGHT: 496,
POPOVER_MENU_MAX_HEIGHT_MOBILE: 432,
POPOVER_DATE_WIDTH: 338,
POPOVER_DATE_RANGE_WIDTH: 672,
POPOVER_DATE_MAX_HEIGHT: 366,
POPOVER_DATE_MIN_HEIGHT: 322,
TOOLTIP_ANIMATION_DURATION: 500,
Expand Down Expand Up @@ -7728,6 +7729,7 @@ const CONST = {
EQUAL_TO: 'eq',
CONTAINS: 'contains',
NOT_EQUAL_TO: 'neq',
RANGE: 'range',
GREATER_THAN: 'gt',
GREATER_THAN_OR_EQUAL_TO: 'gte',
LOWER_THAN: 'lt',
Expand Down Expand Up @@ -7802,6 +7804,7 @@ const CONST = {
ON_PREFIX: 'reportFieldOn-',
AFTER_PREFIX: 'reportFieldAfter-',
BEFORE_PREFIX: 'reportFieldBefore-',
RANGE_PREFIX: 'reportFieldRange-',
},
TAG_EMPTY_VALUE: 'none',
CATEGORY_EMPTY_VALUE: 'none',
Expand Down Expand Up @@ -7931,11 +7934,16 @@ const CONST = {
ON: 'On',
AFTER: 'After',
BEFORE: 'Before',
RANGE: 'Range',
},
get CUSTOM_DATE_MODIFIERS() {
return [this.DATE_MODIFIERS.ON, this.DATE_MODIFIERS.BEFORE, this.DATE_MODIFIERS.AFTER] as const;
},
DATE_FILTER_SUB_PAGE: {
ON: 'on',
AFTER: 'after',
BEFORE: 'before',
RANGE: 'range',
},
AMOUNT_MODIFIERS: {
LESS_THAN: 'LessThan',
Expand Down
22 changes: 19 additions & 3 deletions src/components/DatePicker/CalendarPicker/Day.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -23,17 +24,32 @@ type DayProps = {
};

function Day({disabled, selected, pressed, hovered, children}: DayProps) {
const theme = useTheme();
const themeStyles = useThemeStyles();
const StyleUtils = useStyleUtils();
return (
<View
style={[
themeStyles.calendarDayContainer,
selected ? themeStyles.buttonDefaultBG : {},
!disabled ? StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed)) : {},
// Always provide an explicit backgroundColor so Android (which
// does not reset a property when the style changes to {})
// correctly transitions the selection highlight on every render.
{backgroundColor: selected ? theme.success : theme.transparent},
!disabled && !selected ? StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed), true) : {},
]}
>
<Text style={disabled ? themeStyles.buttonOpacityDisabled : {}}>{children}</Text>
<Text
style={[
disabled ? themeStyles.buttonOpacityDisabled : {},
// Always provide an explicit color so Android repaints text
// correctly when selection changes. Using {} causes Android
// to retain the previous white color after deselection,
// making the day number invisible against the background.
{color: selected ? theme.buttonSuccessText : theme.text},
]}
>
{children}
</Text>
</View>
);
}
Expand Down
29 changes: 21 additions & 8 deletions src/components/DatePicker/CalendarPicker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {addMonths, endOfDay, endOfMonth, format, getYear, isSameDay, parseISO, setDate, setYear, startOfDay, startOfMonth, subMonths} from 'date-fns';
import {Str} from 'expensify-common';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
Expand Down Expand Up @@ -35,6 +36,9 @@ type CalendarPickerProps = {

/** A function called when the date is selected */
onSelected?: (selectedDate: string) => void;

/** Optional style override for the header container */
headerContainerStyle?: StyleProp<ViewStyle>;
};

function getInitialCurrentDateView(value: Date | string, minDate: Date, maxDate: Date) {
Expand All @@ -56,6 +60,7 @@ function CalendarPicker({
onSelected,
DayComponent = Day,
selectableDates,
headerContainerStyle,
}: CalendarPickerProps) {
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {isSmallScreenWidth} = useResponsiveLayout();
Expand Down Expand Up @@ -104,11 +109,9 @@ function CalendarPicker({
* @param day - The day of the month that was selected.
*/
const onDayPressed = (day: number) => {
setCurrentDateView((prev) => {
const newCurrentDateView = setDate(new Date(prev), day);
onSelected?.(format(new Date(newCurrentDateView), CONST.DATE.FNS_FORMAT_STRING));
return newCurrentDateView;
});
const newCurrentDateView = setDate(new Date(currentDateView), day);
setCurrentDateView(newCurrentDateView);
onSelected?.(format(newCurrentDateView, CONST.DATE.FNS_FORMAT_STRING));
};

/**
Expand Down Expand Up @@ -175,13 +178,19 @@ function CalendarPicker({

const webOnlyMarginStyle = isSmallScreenWidth ? {} : styles.mh1;
const calendarContainerStyle = isSmallScreenWidth ? [webOnlyMarginStyle, themeStyles.calendarBodyContainer] : [webOnlyMarginStyle, animatedStyle];
const headerPaddingStyle = headerContainerStyle ?? themeStyles.ph5;
// On mobile (isSmallScreenWidth is always true on native), the height animation is skipped
// so using Animated.View is unnecessary. Using a plain View with collapsable={false} avoids
// activating Reanimated's Fabric commit hook, which on Android can interfere with React's
// reconciliation of child view styles and prevent day-selection background changes from painting.
const CalendarBody = isSmallScreenWidth ? View : Animated.View;

const getAccessibilityState = useCallback((isSelected: boolean) => ({selected: isSelected}), []);

return (
<View style={[themeStyles.pb4]}>
<View
style={[themeStyles.calendarHeader, themeStyles.flexRow, themeStyles.justifyContentBetween, themeStyles.alignItemsCenter, themeStyles.ph5]}
style={[themeStyles.calendarHeader, themeStyles.flexRow, themeStyles.justifyContentBetween, themeStyles.alignItemsCenter, headerPaddingStyle]}
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
<PressableWithFeedback
Expand Down Expand Up @@ -255,10 +264,14 @@ function CalendarPicker({
</View>
))}
</View>
<Animated.View style={calendarContainerStyle}>
<CalendarBody
collapsable={false}
style={calendarContainerStyle}
>
{calendarDaysMatrix?.map((week) => (
<View
key={`week-${week.toString()}`}
collapsable={false}
style={[themeStyles.flexRow, themeStyles.calendarWeekContainer]}
>
{week.map((day, index) => {
Expand Down Expand Up @@ -311,7 +324,7 @@ function CalendarPicker({
})}
</View>
))}
</Animated.View>
</CalendarBody>
<YearPickerModal
isVisible={isYearPickerVisible}
years={years}
Expand Down
Loading
Loading