diff --git a/src/settings/Visits.tsx b/src/settings/Visits.tsx index 6100cb5b..a64a9641 100644 --- a/src/settings/Visits.tsx +++ b/src/settings/Visits.tsx @@ -14,6 +14,7 @@ export const Visits: FC = ({ settings, setVisitsSettings }) => ( setVisitsSettings({ defaultInterval })} /> diff --git a/src/utils/dates/DateIntervalDropdownItems.tsx b/src/utils/dates/DateIntervalDropdownItems.tsx index b1ea2208..57099496 100644 --- a/src/utils/dates/DateIntervalDropdownItems.tsx +++ b/src/utils/dates/DateIntervalDropdownItems.tsx @@ -4,11 +4,16 @@ import { DATE_INTERVALS, DateInterval, rangeOrIntervalToString } from './types'; export interface DateIntervalDropdownProps { active?: DateInterval; + allText: string; onChange: (interval: DateInterval) => void; } -export const DateIntervalDropdownItems: FC = ({ active, onChange }) => ( +export const DateIntervalDropdownItems: FC = ({ active, allText, onChange }) => ( <> + onChange('all')}> + {allText} + + {DATE_INTERVALS.map( (interval) => ( onChange(interval)}> diff --git a/src/utils/dates/DateIntervalSelector.tsx b/src/utils/dates/DateIntervalSelector.tsx index 59d741db..047fccf0 100644 --- a/src/utils/dates/DateIntervalSelector.tsx +++ b/src/utils/dates/DateIntervalSelector.tsx @@ -3,8 +3,8 @@ import { DropdownBtn } from '../DropdownBtn'; import { rangeOrIntervalToString } from './types'; import { DateIntervalDropdownItems, DateIntervalDropdownProps } from './DateIntervalDropdownItems'; -export const DateIntervalSelector: FC = ({ onChange, active }) => ( - - +export const DateIntervalSelector: FC = ({ onChange, active, allText }) => ( + + ); diff --git a/src/utils/dates/DateRangeSelector.tsx b/src/utils/dates/DateRangeSelector.tsx index 4b6212b8..9bd237f1 100644 --- a/src/utils/dates/DateRangeSelector.tsx +++ b/src/utils/dates/DateRangeSelector.tsx @@ -4,10 +4,10 @@ import { DropdownBtn } from '../DropdownBtn'; import { DateInterval, DateRange, - dateRangeIsEmpty, rangeOrIntervalToString, intervalToDateRange, rangeIsInterval, + dateRangeIsEmpty, } from './types'; import DateRangeRow from './DateRangeRow'; import { DateIntervalDropdownItems } from './DateIntervalDropdownItems'; @@ -33,7 +33,7 @@ export const DateRangeSelector = ( setActiveDateRange(dateRange); onDatesChange(dateRange); }; - const updateInterval = (dateInterval?: DateInterval) => () => { + const updateInterval = (dateInterval: DateInterval) => () => { setActiveInterval(dateInterval); setActiveDateRange(undefined); onDatesChange(intervalToDateRange(dateInterval)); @@ -41,14 +41,11 @@ export const DateRangeSelector = ( return ( - - {defaultText} - - - updateInterval(interval)()} /> + updateInterval(interval)()} + /> Custom: diff --git a/src/utils/dates/types/index.ts b/src/utils/dates/types/index.ts index 88672d36..467a0e8f 100644 --- a/src/utils/dates/types/index.ts +++ b/src/utils/dates/types/index.ts @@ -7,14 +7,15 @@ export interface DateRange { endDate?: Date | null; } -export type DateInterval = 'today' | 'yesterday' | 'last7Days' | 'last30Days' | 'last90Days' | 'last180days' | 'last365Days'; +export type DateInterval = 'all' | 'today' | 'yesterday' | 'last7Days' | 'last30Days' | 'last90Days' | 'last180days' | 'last365Days'; export const dateRangeIsEmpty = (dateRange?: DateRange): boolean => dateRange === undefined || isEmpty(filter(Boolean, dateRange as any)); -export const rangeIsInterval = (range?: DateRange | DateInterval): range is DateInterval => typeof range === 'string'; +export const rangeIsInterval = (range?: DateRange | DateInterval): range is DateInterval => + typeof range === 'string'; -const INTERVAL_TO_STRING_MAP: Record = { +const INTERVAL_TO_STRING_MAP: Record = { today: 'Today', yesterday: 'Yesterday', last7Days: 'Last 7 days', @@ -22,9 +23,10 @@ const INTERVAL_TO_STRING_MAP: Record = { last90Days: 'Last 90 days', last180days: 'Last 180 days', last365Days: 'Last 365 days', + all: undefined, }; -export const DATE_INTERVALS: DateInterval[] = Object.keys(INTERVAL_TO_STRING_MAP) as DateInterval[]; +export const DATE_INTERVALS = Object.keys(INTERVAL_TO_STRING_MAP).filter((value) => value !== 'all') as DateInterval[]; const dateRangeToString = (range?: DateRange): string | undefined => { if (!range || dateRangeIsEmpty(range)) { @@ -43,7 +45,7 @@ const dateRangeToString = (range?: DateRange): string | undefined => { }; export const rangeOrIntervalToString = (range?: DateRange | DateInterval): string | undefined => { - if (!range) { + if (!range || range === 'all') { return undefined; } @@ -58,7 +60,7 @@ const startOfDaysAgo = (daysAgo: number) => startOfDay(subDays(new Date(), daysA const endingToday = (startDate: Date): DateRange => ({ startDate, endDate: endOfDay(new Date()) }); export const intervalToDateRange = (dateInterval?: DateInterval): DateRange => { - if (!dateInterval) { + if (!dateInterval || dateInterval === 'all') { return {}; } diff --git a/test/utils/dates/DateIntervalDropdownItems.test.tsx b/test/utils/dates/DateIntervalDropdownItems.test.tsx index 2d15ebd8..d77fb1e4 100644 --- a/test/utils/dates/DateIntervalDropdownItems.test.tsx +++ b/test/utils/dates/DateIntervalDropdownItems.test.tsx @@ -8,7 +8,7 @@ describe('', () => { const onChange = jest.fn(); beforeEach(() => { - wrapper = shallow(); + wrapper = shallow(); }); afterEach(jest.clearAllMocks); @@ -16,24 +16,26 @@ describe('', () => { it('renders expected amount of items', () => { const items = wrapper.find(DropdownItem); + const dividerItems = items.findWhere((item) => !!item.prop('divider')); - expect(items).toHaveLength(DATE_INTERVALS.length); + expect(items).toHaveLength(DATE_INTERVALS.length + 2); + expect(dividerItems).toHaveLength(1); }); it('sets expected item as active', () => { - const items = wrapper.find(DropdownItem); - const EXPECTED_ACTIVE_INDEX = 5; + const items = wrapper.find(DropdownItem).findWhere((item) => item.prop('active') !== undefined); + const EXPECTED_ACTIVE_INDEX = 6; - expect.assertions(DATE_INTERVALS.length); + expect.assertions(DATE_INTERVALS.length + 1); items.forEach((item, index) => expect(item.prop('active')).toEqual(index === EXPECTED_ACTIVE_INDEX)); }); it('triggers onChange callback when selecting an element', () => { const items = wrapper.find(DropdownItem); - items.at(2).simulate('click'); items.at(4).simulate('click'); - items.at(1).simulate('click'); + items.at(6).simulate('click'); + items.at(3).simulate('click'); expect(onChange).toHaveBeenCalledTimes(3); }); }); diff --git a/test/utils/dates/DateIntervalSelector.test.tsx b/test/utils/dates/DateIntervalSelector.test.tsx index 94c068d7..2b73da55 100644 --- a/test/utils/dates/DateIntervalSelector.test.tsx +++ b/test/utils/dates/DateIntervalSelector.test.tsx @@ -10,7 +10,7 @@ describe('', () => { const onChange = jest.fn(); beforeEach(() => { - wrapper = shallow(); + wrapper = shallow(); }); afterEach(() => wrapper?.unmount()); @@ -22,5 +22,6 @@ describe('', () => { expect(items).toHaveLength(1); expect(items.prop('onChange')).toEqual(onChange); expect(items.prop('active')).toEqual(activeInterval); + expect(items.prop('allText')).toEqual('All text'); }); }); diff --git a/test/utils/dates/DateRangeSelector.test.tsx b/test/utils/dates/DateRangeSelector.test.tsx index cb599c90..ef794918 100644 --- a/test/utils/dates/DateRangeSelector.test.tsx +++ b/test/utils/dates/DateRangeSelector.test.tsx @@ -4,12 +4,19 @@ import { Mock } from 'ts-mockery'; import { DateRangeSelector, DateRangeSelectorProps } from '../../../src/utils/dates/DateRangeSelector'; import { DateInterval } from '../../../src/utils/dates/types'; import { DateIntervalDropdownItems } from '../../../src/utils/dates/DateIntervalDropdownItems'; +import DateRangeRow from '../../../src/utils/dates/DateRangeRow'; describe('', () => { let wrapper: ShallowWrapper; const onDatesChange = jest.fn(); const createWrapper = (props: Partial = {}) => { - wrapper = shallow((props)} onDatesChange={onDatesChange} />); + wrapper = shallow( + (props)} + defaultText="Default text" + onDatesChange={onDatesChange} + />, + ); return wrapper; }; @@ -22,47 +29,48 @@ describe('', () => { const items = wrapper.find(DropdownItem); const dateIntervalItems = wrapper.find(DateIntervalDropdownItems); - expect(items).toHaveLength(5); + expect(items).toHaveLength(3); expect(dateIntervalItems).toHaveLength(1); - expect(items.filter('[divider]')).toHaveLength(2); + expect(items.filter('[divider]')).toHaveLength(1); expect(items.filter('[header]')).toHaveLength(1); expect(items.filter('[text]')).toHaveLength(1); - expect(items.filter('[active]')).toHaveLength(1); }); it.each([ - [ undefined, 1, 0 ], - [ 'today' as DateInterval, 0, 1 ], - [ 'yesterday' as DateInterval, 0, 1 ], - [ 'last7Days' as DateInterval, 0, 1 ], - [ 'last30Days' as DateInterval, 0, 1 ], - [ 'last90Days' as DateInterval, 0, 1 ], - [ 'last180days' as DateInterval, 0, 1 ], - [ 'last365Days' as DateInterval, 0, 1 ], - [{ startDate: new Date() }, 0, 0 ], - ])('sets proper element as active based on provided date range', ( - initialDateRange, - expectedActiveItems, - expectedActiveIntervalItems, - ) => { + [ undefined, 0 ], + [ 'all' as DateInterval, 1 ], + [ 'today' as DateInterval, 1 ], + [ 'yesterday' as DateInterval, 1 ], + [ 'last7Days' as DateInterval, 1 ], + [ 'last30Days' as DateInterval, 1 ], + [ 'last90Days' as DateInterval, 1 ], + [ 'last180days' as DateInterval, 1 ], + [ 'last365Days' as DateInterval, 1 ], + [{ startDate: new Date() }, 0 ], + ])('sets proper element as active based on provided date range', (initialDateRange, expectedActiveIntervalItems) => { const wrapper = createWrapper({ initialDateRange }); - const items = wrapper.find(DropdownItem).filterWhere((item) => item.prop('active') === true); const dateIntervalItems = wrapper.find(DateIntervalDropdownItems).filterWhere( (item) => item.prop('active') !== undefined, ); - expect(items).toHaveLength(expectedActiveItems); expect(dateIntervalItems).toHaveLength(expectedActiveIntervalItems); }); it('triggers onDatesChange callback when selecting an element', () => { const wrapper = createWrapper(); - const item = wrapper.find(DropdownItem).at(0); + const dates = wrapper.find(DateRangeRow); const dateIntervalItems = wrapper.find(DateIntervalDropdownItems); - item.simulate('click'); - item.simulate('click'); + dates.simulate('startDateChange', null); + dates.simulate('endDateChange', null); dateIntervalItems.simulate('change'); expect(onDatesChange).toHaveBeenCalledTimes(3); }); + + it('propagates default text to DateIntervalDropdownItems', () => { + const wrapper = createWrapper(); + const dateIntervalItems = wrapper.find(DateIntervalDropdownItems); + + expect(dateIntervalItems.prop('allText')).toEqual('Default text'); + }); });