/**
* External dependencies
*/
import { useRef, useState, useEffect } from '@wordpress/element';
import { useDispatch } from 'react-redux';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBars } from '@fortawesome/free-solid-svg-icons';
import 'react-date-range/dist/styles.css';
import 'react-date-range/dist/theme/default.css';
import { DateRangePicker, Calendar } from 'react-date-range';
import { format, subDays } from 'date-fns';
/**
* Internal dependencies
*/
import DatePickerData, { IDatePickerData } from './DatePickerData';
import { changeDateFilterAction } from '../../../redux/actions/GlobalAction';
import { getCurrentDate, getFormattedDate } from '../../../utils/DateHelper';
import { getGlobalData } from '../../../utils/global-data';
enum Type {
DatePicker = 'date-picker',
DateRangePicker = 'date-range-picker',
}
export type DatePickerType = Type;
export interface IDatePicker {
/**
* Date Picker type.
* It's for both single date-picker and date-range picker.
*/
type: DatePickerType;
/**
* Show months count no in date picker.
* We can show more than 2 months in date-range picker calendar.
*/
showMonthsCount?: number;
/**
* Start date in calendar.
*/
startDate?: Date | undefined;
/**
* Update start date.
*/
setStartDate?: Function;
/**
* End date of date-range picker type calendar.
*/
endDate?: Date | undefined;
/**
* Update end date.
*/
setEndDate?: Function;
}
const DatePickerProps = {
type: 'date-picker' as DatePickerType,
showMonthsCount: 2,
startDate: new Date(),
setStartDate: () => {},
endDate: undefined,
setEndDate: () => {},
};
const DatePicker = (props: IDatePicker) => {
const { type, startDate, setStartDate, endDate, setEndDate } = props;
const dispatch = useDispatch();
const ref = useRef(null);
const [showDate, setShowDate] = useState(false);
const last30DayPicker = DatePickerData().filter(
(item: IDatePickerData) => item.value === 'last30Days'
)[0];
const [selectedPicker, setSelectedPicker] = useState(last30DayPicker);
const showMonthsCount =
typeof props.showMonthsCount !== 'undefined'
? props.showMonthsCount
: DatePickerProps.showMonthsCount;
const [dateData, setDateData] = useState([
{
startDate: subDays(new Date(), 30),
endDate: new Date(),
key: 'selection',
},
]);
/**
* Handle Outside click of date picker.
*
* @param event object
*/
const handleClickOutside = (event: object) => {
if (ref.current && !ref.current.contains(event.target)) {
setShowDate(false);
}
};
/**
* Handle Outside click of the component.
*/
useEffect(() => {
document.addEventListener('click', handleClickOutside, true);
return () => {
document.removeEventListener('click', handleClickOutside, true);
};
});
/**
* Select Date Picker.
*
* @param data IDatePickerData
*/
const selectPicker = (data: IDatePickerData) => {
setSelectedPicker(data);
if (data.value !== 'customRange') {
setShowDate(false);
// if data.value is for allTime, then set startDate and endDate to biggest date
if (data.value === 'allTime') {
const initialStartDate =
typeof getGlobalData('installed_at') !== 'string'
? new Date(0)
: new Date(getGlobalData('installed_at'));
data.startDate = getFormattedDate(initialStartDate);
data.endDate = getCurrentDate();
}
dispatch(
changeDateFilterAction(data.startDate, data.endDate, data.value)
);
typeof setStartDate === 'function' &&
setStartDate(new Date(data.startDate));
typeof setEndDate === 'function' &&
setEndDate(new Date(data.endDate));
}
if (data.value === 'customRange' && data.startDate && data.endDate) {
typeof setStartDate === 'function' && setStartDate(data.startDate);
typeof setEndDate === 'function' && setEndDate(data.endDate);
setShowDate(false);
dispatch(
changeDateFilterAction(
getFormattedDate(new Date(data.startDate)),
getFormattedDate(new Date(data.endDate)),
data.value
)
);
}
};
return (
<span ref={ref}>
<span
className="bg-white border border-solid border-gray-lite text-gray-dark rounded h-9 w-24 justify-end justify-self-end pb-2 pt-2 pr-3 md:pl-4 sm:pl-2 cursor-pointer"
onClick={() => setShowDate(!showDate)}
>
<span className="w-10 mr-2 md:text-sm sm:text-xs">
{typeof startDate !== 'undefined'
? format(startDate, 'MMM dd, yyyy')
: ''}
{typeof endDate !== 'undefined' && endDate !== null && (
<> ? {format(endDate, 'MMM dd, yyyy')}</>
)}
</span>
<span className=" pl-2 w-6 h-6 border-l border-solid">
<FontAwesomeIcon icon={faBars} className="text-base" />
</span>
</span>
{showDate && (
<div className="absolute bg-white right-7 p-2 mt-4 shadow z-10 mr-4">
{type === 'date-picker' && (
<Calendar
date={new Date()}
onChange={(date) => {
if (typeof setStartDate !== 'undefined') {
setStartDate(date);
}
if (typeof setEndDate !== 'undefined') {
setEndDate(date);
}
setShowDate(false);
}}
editableDateInputs={true}
/>
)}
<div className="bg-white">
<ul className="list-none ml-0">
{DatePickerData().map((data, index) => {
return (
<li
key={index}
className={`border-b border-solid border-gray-liter p-2 cursor-pointer hover:bg-gray-liter text-left min-w-36 ${
selectedPicker.value === data.value
? 'bg-gray-liter'
: ''
}`}
onClick={() => selectPicker(data)}
>
{data.name}
</li>
);
})}
</ul>
</div>
{selectedPicker.value === 'customRange' &&
type === 'date-range-picker' && (
<DateRangePicker
onChange={(item) => {
setDateData([item.selection]);
const customDateRange =
DatePickerData().filter(
(item: IDatePickerData) =>
item.value === 'customRange'
)[0];
customDateRange.startDate =
item.selection.startDate;
customDateRange.endDate =
item.selection.endDate;
selectPicker(customDateRange);
}}
showSelectionPreview={false}
showDateDisplay={false}
moveRangeOnFirstSelection={false}
months={showMonthsCount}
ranges={dateData}
direction="horizontal"
editableDateInputs={true}
onRangeFocusChange={() => setShowDate(false)}
/>
)}
</div>
)}
</span>
);
};
DatePicker.defaultProps = DatePickerProps;
export default DatePicker;
|