diff --git a/packages/shared-ui/src/components/DatePicker/index.tsx b/packages/shared-ui/src/components/DatePicker/index.tsx index 5ccd5e8f..712839cd 100644 --- a/packages/shared-ui/src/components/DatePicker/index.tsx +++ b/packages/shared-ui/src/components/DatePicker/index.tsx @@ -1,7 +1,7 @@ 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' @@ -9,6 +9,7 @@ import './style.css' export interface IDatePicker { className?: string disabled?: boolean + enableTimer?: boolean title?: string value?: Date onChange?: (d: Date) => void @@ -20,6 +21,7 @@ export default function DatePicker({ title, className, disabled, + enableTimer, value, onChange, toNow = false, @@ -27,17 +29,68 @@ export default function DatePicker({ }: IDatePicker) { const [selected, setSelected] = useState() 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) => { + 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 }) @@ -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 ( + + at {+hour > 12 ? +hour - 12 : hour}:{min} {suffix} + + ) + } + return (
{title ? : null} @@ -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 ? ( {placeholder} ) : ( @@ -74,12 +141,18 @@ export default function DatePicker({ selected={selected} showOutsideDays fixedWeeks - onSelect={value => { - setVisible(false) - setSelected(value) - value && onDatepickerChange(value) - }} + onSelect={onDatepickerChangeHandler} /> + +
+ Pick a time: + +
{/* */} diff --git a/packages/shared-ui/src/components/DatePicker/style.css b/packages/shared-ui/src/components/DatePicker/style.css index f128744f..043c3271 100644 --- a/packages/shared-ui/src/components/DatePicker/style.css +++ b/packages/shared-ui/src/components/DatePicker/style.css @@ -10,18 +10,25 @@ 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) { @@ -29,6 +36,6 @@ } .rdp-day, -.rdp-nav_button{ - @apply rounded +.rdp-nav_button { + @apply rounded; } diff --git a/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalMonthTask.tsx b/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalMonthTask.tsx index bfd42a6b..417fddb6 100644 --- a/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalMonthTask.tsx +++ b/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalMonthTask.tsx @@ -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 || '') @@ -28,17 +37,31 @@ export default function CalMonthTask({ index, id, title, assigneeId, taskStatusI } return ( - - {provided => ( -
- {calendarView === ICalendarView.WEEK ? : - } -
- )} -
+ + + {provided => ( +
+ {calendarView === ICalendarView.WEEK ? ( + + ) : ( + + )} +
+ )} +
+ ) } diff --git a/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalMonthTaskList.tsx b/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalMonthTaskList.tsx index 64059536..87887544 100644 --- a/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalMonthTaskList.tsx +++ b/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalMonthTaskList.tsx @@ -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 ( - - - + ) })}
diff --git a/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalTaskInMonth.tsx b/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalTaskInMonth.tsx index 75758e01..e48aee1f 100644 --- a/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalTaskInMonth.tsx +++ b/packages/ui-app/app/[orgID]/project/[projectId]/calendar/CalTaskInMonth.tsx @@ -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 <> -
-
- {title} - -
- + return ( + <> +
+
+ {title} + +
+
{time}
+ + ) } diff --git a/packages/ui-app/app/_features/TaskDetail/index.tsx b/packages/ui-app/app/_features/TaskDetail/index.tsx index cdaf6a89..43a4f646 100644 --- a/packages/ui-app/app/_features/TaskDetail/index.tsx +++ b/packages/ui-app/app/_features/TaskDetail/index.tsx @@ -14,6 +14,7 @@ import { HiOutlineBattery50, HiOutlineBeaker, HiOutlineBriefcase, + HiOutlineCalendar, HiOutlineChatBubbleLeft, HiOutlineClock, HiOutlineFlag, @@ -153,10 +154,9 @@ export default function TaskDetail({ } }, 200) }} - style={{width: 'calc(100% - 40px)'}} - className={`cursor-pointer font-bold text-2xl select-none ${ - titleVisible ? '' : 'hidden' - }`}> + style={{ width: 'calc(100% - 40px)' }} + className={`cursor-pointer font-bold text-2xl select-none ${titleVisible ? '' : 'hidden' + }`}> {formik.values.title} @@ -217,10 +217,11 @@ export default function TaskDetail({
- Actual Timeline + Due date
{ formik.setFieldValue('dueDate', d) @@ -230,7 +231,7 @@ export default function TaskDetail({
- Timeline + Planned date
@@ -318,89 +319,6 @@ export default function TaskDetail({
- - {/*
*/} - {/*
*/} - {/* */} - {/* { */} - {/* formik.setFieldValue('progress', v) */} - {/* }} */} - {/* /> */} - {/* { */} - {/* formik.setFieldValue('desc', v) */} - {/* }} */} - {/* /> */} - {/* {isUpdate ? : null} */} - {/* {isUpdate ? : null} */} - {/*
*/} - {/* */} - {/*
*/} ) }