Skip to content

Instantly share code, notes, and snippets.

@ever-dev
Created November 8, 2019 22:47
Show Gist options
  • Save ever-dev/d065f69137c545e56bc924e30e12f4c3 to your computer and use it in GitHub Desktop.
Save ever-dev/d065f69137c545e56bc924e30e12f4c3 to your computer and use it in GitHub Desktop.
/** @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