RocketChat/Rocket.Chat

View on GitHub
apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
import { Box, InputBox, Menu, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { Moment } from 'moment';
import moment from 'moment';
import type { ComponentProps } from 'react';
import React, { useState, useMemo, useEffect } from 'react';

moment.locale('en');

type DateRangePickerProps = Omit<ComponentProps<typeof Box>, 'onChange'> & {
    onChange(range: { start: string; end: string }): void;
};

const formatToDateInput = (date: Moment) => date.format('YYYY-MM-DD');

const todayDate = formatToDateInput(moment());

const getMonthRange = (monthsToSubtractFromToday: number) => ({
    start: formatToDateInput(moment().subtract(monthsToSubtractFromToday, 'month').date(1)),
    end: formatToDateInput(monthsToSubtractFromToday === 0 ? moment() : moment().subtract(monthsToSubtractFromToday).date(0)),
});

const getWeekRange = (daysToSubtractFromStart: number, daysToSubtractFromEnd: number) => ({
    start: formatToDateInput(moment().subtract(daysToSubtractFromStart, 'day')),
    end: formatToDateInput(moment().subtract(daysToSubtractFromEnd, 'day')),
});

const DateRangePicker = ({ onChange = () => undefined, ...props }: DateRangePickerProps) => {
    const t = useTranslation();
    const [range, setRange] = useState({ start: '', end: '' });

    const { start, end } = range;

    const handleStart = useMutableCallback(({ currentTarget }) => {
        const rangeObj = {
            start: currentTarget.value,
            end: range.end,
        };
        setRange(rangeObj);
        onChange(rangeObj);
    });

    const handleEnd = useMutableCallback(({ currentTarget }) => {
        const rangeObj = {
            end: currentTarget.value,
            start: range.start,
        };
        setRange(rangeObj);
        onChange(rangeObj);
    });

    const handleRange = useMutableCallback((range) => {
        setRange(range);
        onChange(range);
    });

    useEffect(() => {
        handleRange({
            start: todayDate,
            end: todayDate,
        });
    }, [handleRange]);

    const options = useMemo(
        () => ({
            today: {
                icon: 'history',
                label: t('Today'),
                action: () => {
                    handleRange(getWeekRange(0, 0));
                },
            },
            yesterday: {
                icon: 'history',
                label: t('Yesterday'),
                action: () => {
                    handleRange(getWeekRange(1, 1));
                },
            },
            thisWeek: {
                icon: 'history',
                label: t('This_week'),
                action: () => {
                    handleRange(getWeekRange(7, 0));
                },
            },
            previousWeek: {
                icon: 'history',
                label: t('Previous_week'),
                action: () => {
                    handleRange(getWeekRange(14, 7));
                },
            },
            thisMonth: {
                icon: 'history',
                label: t('This_month'),
                action: () => {
                    handleRange(getMonthRange(0));
                },
            },
            lastMonth: {
                icon: 'history',
                label: t('Previous_month'),
                action: () => {
                    handleRange(getMonthRange(1));
                },
            },
        }),
        [handleRange, t],
    );

    return (
        <Box {...props}>
            <Box mi='neg-x4' height='full' display='flex' flexDirection='row'>
                <Field mi={4} flexShrink={1} flexGrow={1}>
                    <FieldLabel>{t('Start')}</FieldLabel>
                    <FieldRow>
                        <Box height='x40' display='flex' width='full'>
                            <InputBox type='date' onChange={handleStart} max={todayDate} value={start} />
                        </Box>
                    </FieldRow>
                </Field>
                <Field mi={4} flexShrink={1} flexGrow={1}>
                    <FieldLabel>{t('End')}</FieldLabel>
                    <FieldRow>
                        <Box height='x40' display='flex' width='full'>
                            <InputBox type='date' onChange={handleEnd} min={start} max={todayDate} value={end} />
                        </Box>
                        <Menu mis={8} options={options} />
                    </FieldRow>
                </Field>
            </Box>
        </Box>
    );
};

export default DateRangePicker;