Created
November 8, 2019 22:47
-
-
Save ever-dev/d065f69137c545e56bc924e30e12f4c3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @jsx jsx */ | |
import { jsx } from '@emotion/core' | |
import { FunctionComponent, HTMLAttributes, useMemo, useState, useEffect } from 'react' | |
import Calendar from 'react-calendar/dist/entry.nostyle' | |
import dayjs from 'dayjs' | |
import { Icon, Button, Clickover, Text } from '~/components' | |
import { styles } from './styles' | |
// @ts-ignore | |
interface DatePickerProps extends HTMLAttributes<HTMLDivElement> { | |
value: [Date, Date] | |
onChange: (date: [Date, Date]) => any | |
} | |
export const DatePicker: FunctionComponent<DatePickerProps> = ({ | |
value: [from, to] = [], | |
onChange, | |
}) => { | |
const [formattedFrom, formattedTo] = useMemo( | |
() => [from, to].map((d) => dayjs(d).format('MMM D, YYYY')), | |
[from, to], | |
) | |
return ( | |
<Clickover | |
position={['right', 'top']} // preferred position | |
Content={({ closePopup }) => ( | |
<DatePopup | |
onChange={onChange} | |
closePopup={closePopup} | |
value={[from || new Date(), to || new Date()]} | |
/> | |
)} | |
> | |
<div css={styles.container} data-test-id="datepicker-target"> | |
<span css={styles.date.container}> | |
{from && to ? ( | |
<span data-test-id="selected-value"> | |
{formattedFrom + ' ~ ' + formattedTo} | |
</span> | |
) : ( | |
<span>Choose date</span> | |
)} | |
</span> | |
<Icon icon="calendar" color="#6d7d84" size={17} /> | |
</div> | |
</Clickover> | |
) | |
} | |
// @ts-ignore | |
interface DatePopupProps extends HTMLAttributes<HTMLDivElement> { | |
value: [Date, Date] | |
onChange: (date: [Date, Date]) => any | |
closePopup: () => any | |
} | |
const checkMode = (dateRange: Date[]) => { | |
const now = dayjs() | |
const checkMode = [ | |
[now.subtract(6, 'day'), now], | |
[now.subtract(29, 'day'), now], | |
[now.subtract(1, 'month').startOf('month'), now.subtract(1, 'month').endOf('month')], | |
] | |
let mode = checkMode.findIndex( | |
(mode) => | |
dateRange.map((date) => dayjs(date).format('YYYY-MM-DD')).join() === | |
mode.map((day) => day.format('YYYY-MM-DD')).join(), | |
) | |
if (mode === -1) { | |
mode = 3 | |
} | |
return mode | |
} | |
const getRange = (mode: number) => { | |
const now = dayjs() | |
const checkMode = [ | |
[now.subtract(6, 'day'), now], | |
[now.subtract(29, 'day'), now], | |
[now.subtract(1, 'month').startOf('month'), now.subtract(1, 'month').endOf('month')], | |
] | |
return checkMode[mode].map((day) => day.toDate()) | |
} | |
const DatePopup: FunctionComponent<DatePopupProps> = ({ | |
onChange, | |
closePopup, | |
value: [from, to], | |
}) => { | |
const [dateRange, setDateRange] = useState([from, to]) | |
const [showCalendar, toggleCalendar] = useState(false) | |
const [change, setChange] = useState(false) | |
useEffect(() => { | |
if (checkMode(dateRange) === 3 && showCalendar === false) { | |
toggleCalendar(true) | |
} | |
if (change) { | |
onChange([dateRange[0], dateRange[1]]) | |
closePopup() | |
} | |
}, [dateRange]) | |
return ( | |
<div css={styles.popup.container} data-test-id="date-picker-popup"> | |
<div css={styles.popup.menu}> | |
<div css={styles.popup.title}> | |
<Text type="primary">Date Range</Text> | |
</div> | |
<ul> | |
<li | |
css={checkMode(dateRange) === 0 && styles.popup.selectedMode} | |
onClick={() => { | |
setChange(true) | |
setDateRange(getRange(0)) | |
}} | |
data-test-id="date-picker-option1" | |
> | |
Last 7 days | |
</li> | |
<li | |
css={checkMode(dateRange) === 1 && styles.popup.selectedMode} | |
onClick={() => { | |
setChange(true) | |
setDateRange(getRange(1)) | |
}} | |
data-test-id="date-picker-option2" | |
> | |
Last 30 days | |
</li> | |
<li | |
css={checkMode(dateRange) === 2 && styles.popup.selectedMode} | |
onClick={() => { | |
setChange(true) | |
setDateRange(getRange(2)) | |
}} | |
data-test-id="date-picker-option3" | |
> | |
Last Month | |
</li> | |
<li | |
css={checkMode(dateRange) === 3 && styles.popup.selectedMode} | |
onClick={() => toggleCalendar(true)} | |
data-test-id="date-picker-option4" | |
> | |
Custom Range | |
</li> | |
</ul> | |
<div css={styles.popup.selected.container}> | |
<div css={styles.popup.selected.item}> | |
<span>From</span> | |
{dayjs(dateRange[0]).format('MM-DD-YYYY')} | |
</div> | |
<div css={styles.popup.selected.item}> | |
<span>To</span> | |
{dayjs(dateRange[1]).format('MM-DD-YYYY')} | |
</div> | |
</div> | |
</div> | |
{showCalendar && ( | |
<div css={styles.popup.select}> | |
<Calendar | |
selectRange={true} | |
onChange={(e: Date[]) => setDateRange(e)} | |
value={dateRange} | |
returnValue="range" | |
css={styles.calendar} | |
data-test-id="date-picker-calendar" | |
/> | |
<div css={styles.popup.buttons}> | |
<Button | |
color="white" | |
size="tiny" | |
onClick={() => closePopup()} | |
data-test-id="cancel-btn" | |
> | |
Cancel | |
</Button> | |
<Button | |
color="accent" | |
size="tiny" | |
onClick={() => { | |
onChange([dateRange[0], dateRange[1]]) | |
closePopup() | |
}} | |
data-test-id="apply-btn" | |
> | |
Apply | |
</Button> | |
</div> | |
</div> | |
)} | |
</div> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment