Skip to content

Commit

Permalink
improve: add datepicker timer (#141)
Browse files Browse the repository at this point in the history
  • Loading branch information
hudy9x authored Mar 14, 2024
1 parent 587c43f commit 301d34c
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 139 deletions.
89 changes: 81 additions & 8 deletions packages/shared-ui/src/components/DatePicker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { format, formatDistanceToNowStrict, isValid } from 'date-fns'
import * as Popover from '@radix-ui/react-popover'
import { useEffect, useState } from 'react'
import { DayPicker } from 'react-day-picker'
import { ChangeEvent, useEffect, useState } from 'react'
import { DayPicker, SelectSingleEventHandler } from 'react-day-picker'
import { AiOutlineCalendar } from 'react-icons/ai'
import 'react-day-picker/dist/style.css'
import './style.css'

export interface IDatePicker {
className?: string
disabled?: boolean
enableTimer?: boolean
title?: string
value?: Date
onChange?: (d: Date) => void
Expand All @@ -20,24 +21,76 @@ export default function DatePicker({
title,
className,
disabled,
enableTimer,
value,
onChange,
toNow = false,
placeholder
}: IDatePicker) {
const [selected, setSelected] = useState<Date>()
const [visible, setVisible] = useState(false)
const [time, setTime] = useState(
`${selected?.getHours()}:${selected?.getMinutes()}`
)

// fill default value
useEffect(() => {
setSelected(value)
if (value) {
const h = value.getHours()
const m = value.getMinutes()

setTime(`${h > 9 ? h : '0' + h}:${m > 9 ? m : '0' + m}`)
}
// value && setSelected(value)
}, [value])

const extractHourNMin = (time: string) => {
const [hour, min] = time.split(':')
return { hour, min }
}

const onDatepickerChangeHandler: SelectSingleEventHandler = value => {
setVisible(false)
setSelected(value)
if (value) {
const [hour, min] = time.split(':')

onDatepickerChange(
new Date(
value.getFullYear(),
value.getMonth(),
value.getDate(),
+hour,
+min
)
)
}
}

const onDatepickerChange = (d: Date) => {
onChange && onChange(d)
}

const onTimerChangeHandler = (ev: ChangeEvent<HTMLInputElement>) => {
const time = ev.target.value
const [hour, min] = time.split(':')

if (selected) {
onDatepickerChange(
new Date(
selected.getFullYear(),
selected.getMonth(),
selected.getDate(),
+hour,
+min
)
)
}

setTime(time)
}

const showDateStr = (d: Date) => {
if (toNow) {
return formatDistanceToNowStrict(d, { addSuffix: true })
Expand All @@ -46,6 +99,17 @@ export default function DatePicker({
return format(d, 'PP')
}

const showTimer = () => {
if (!enableTimer) return null
const { hour, min } = extractHourNMin(time)
const suffix = +hour > 12 ? 'PM' : 'AM'
return (
<span className="pl-1">
at {+hour > 12 ? +hour - 12 : hour}:{min} {suffix}
</span>
)
}

return (
<div className={`form-control ${className}`}>
{title ? <label>{title}</label> : null}
Expand All @@ -57,7 +121,10 @@ export default function DatePicker({
className="form-input cursor-pointer whitespace-nowrap pr-8"
tabIndex={-1}>
{selected && isValid(selected) ? (
showDateStr(selected)
<>
{showDateStr(selected)}
{showTimer()}
</>
) : placeholder ? (
<span className="text-gray-400">{placeholder}</span>
) : (
Expand All @@ -74,12 +141,18 @@ export default function DatePicker({
selected={selected}
showOutsideDays
fixedWeeks
onSelect={value => {
setVisible(false)
setSelected(value)
value && onDatepickerChange(value)
}}
onSelect={onDatepickerChangeHandler}
/>

<div className="rdp-timer-container">
<span>Pick a time:</span>
<input
className="rdp-timer"
type="time"
value={time}
onChange={onTimerChangeHandler}
/>
</div>
{/* <Popover.Arrow className="popover-arrow" /> */}
</Popover.Content>
</Popover.Portal>
Expand Down
19 changes: 13 additions & 6 deletions packages/shared-ui/src/components/DatePicker/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,32 @@
fill: white;
}

.rdp-timer-container {
@apply flex items-center py-3 px-4 justify-between border-t dark:border-gray-700;
}
.rdp-timer {
@apply border-none text-sm bg-white dark:bg-gray-900 p-0;
}

.rdp-caption_label {
@apply text-gray-800;
}
.rdp-nav {
@apply space-x-2
@apply space-x-2;
}
.rdp-nav_button svg {
@apply w-2.5 h-2.5
@apply w-2.5 h-2.5;
}

.rdp-nav_button{
@apply border border-gray-200 w-7 h-7
.rdp-nav_button {
@apply border border-gray-200 w-7 h-7;
}

.rdp-button:hover:not([disabled]):not(.rdp-day_selected) {
@apply bg-gray-100;
}

.rdp-day,
.rdp-nav_button{
@apply rounded
.rdp-nav_button {
@apply rounded;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,27 @@ import CalTaskInMonth from './CalTaskInMonth'
import { ICalendarView, useCalendarContext } from './context'
import CalTaskInWeek from './CalTaskInWeek'
import { useTaskFilter } from '@/features/TaskFilter/context'
import Link from 'next/link'

interface ICalMonthTaskProps {
id: string
link: string
title: string
time: string
assigneeId: string
taskStatusId: string
index: number
}


export default function CalMonthTask({ index, id, title, assigneeId, taskStatusId }: ICalMonthTaskProps) {

export default function CalMonthTask({
index,
link,
time,
id,
title,
assigneeId,
taskStatusId
}: ICalMonthTaskProps) {
const { filter } = useTaskFilter()
const { status: filterStatus } = filter
const { color, type } = useStatusData(taskStatusId || '')
Expand All @@ -28,17 +37,31 @@ export default function CalMonthTask({ index, id, title, assigneeId, taskStatusI
}

return (
<Draggable draggableId={id} index={index}>
{provided => (
<div
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
className="calendar-task-item relative">
{calendarView === ICalendarView.WEEK ? <CalTaskInWeek color={color} title={title} assigneeId={assigneeId} /> :
<CalTaskInMonth color={color} title={title} assigneeId={assigneeId} />}
</div>
)}
</Draggable>
<Link href={link}>
<Draggable draggableId={id} index={index}>
{provided => (
<div
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
className="calendar-task-item relative">
{calendarView === ICalendarView.WEEK ? (
<CalTaskInWeek
color={color}
title={title}
assigneeId={assigneeId}
/>
) : (
<CalTaskInMonth
time={time}
color={color}
title={title}
assigneeId={assigneeId}
/>
)}
</div>
)}
</Draggable>
</Link>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,21 @@ export default function CalMonthTaskList({ day }: { day: Date }) {
return null
}

const h = dueDate.getHours()
const m = dueDate.getMinutes()
const time = `${h > 9 ? h : '0' + h}:${m > 9 ? m : '0' + m}`

return (
<Link key={task.id} href={`${orgID}/project/${projectId}?mode=${mode}&taskId=${task.id}`}>
<CalMonthTask key={task.id}
index={++index}
title={task.title}
id={task.id}
assigneeId={task.assigneeIds[0]}
taskStatusId={task.taskStatusId || ''} />
</Link>
<CalMonthTask
link={`${orgID}/project/${projectId}?mode=${mode}&taskId=${task.id}`}
key={task.id}
time={time}
index={++index}
title={task.title}
id={task.id}
assigneeId={task.assigneeIds[0]}
taskStatusId={task.taskStatusId || ''}
/>
)
})}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import MemberAvatar from "@/components/MemberAvatar";
import MemberAvatar from '@/components/MemberAvatar'

export default function CalTaskInMonth({
color,
time,
title,
assigneeId
}: {
color: string,
title: string,
color: string
time: string
title: string
assigneeId: string
}) {

return <>
<div
className='absolute left-0 top-0 h-full w-[3px]'
style={{ backgroundColor: color }}></div>
<div className="flex items-center justify-between gap-1" title={title}>
<span className="truncate dark:text-gray-400">{title}</span>
<MemberAvatar noName={true} uid={assigneeId} />
</div>
</>
return (
<>
<div
className="absolute left-0 top-0 h-full w-[3px]"
style={{ backgroundColor: color }}></div>
<div className="flex items-center justify-between gap-1" title={title}>
<span className="truncate dark:text-gray-400">{title}</span>
<MemberAvatar noName={true} uid={assigneeId} />
</div>
<div className="text-xs text-gray-400 dark:text-gray-500">{time}</div>
</>
)
}
Loading

0 comments on commit 301d34c

Please sign in to comment.