Skip to content

Commit

Permalink
feat: highlight overdue tasks (#156)
Browse files Browse the repository at this point in the history
* feat: highlight overdue tasks

* remove alert overdue tasks

* only display overdue color in case task is not done

* clean up

---------

Co-authored-by: hudy@mac-air <[email protected]>
  • Loading branch information
huypl53 and hudy9x authored Apr 5, 2024
1 parent 04ce20b commit 4506c63
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ export default function ProjectTabContent() {
const ignored = ['setting', 'automation', 'automation-create']
const isIgnored = () => ignored.includes(mode || '')

console.log('mode', mode)

const type = projectViewMap.get(mode || '') || 'NONE'

const isView = (t: ProjectViewType) => !isIgnored() && type === t
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import MemberAvatar from '@/components/MemberAvatar'
import { useUrl } from '@/hooks/useUrl'
import PriorityText from '@/components/PriorityText'
import { Loading, messageWarning } from '@shared/ui'

import differenceInDays from 'date-fns/differenceInDays'
import { useStatusUtils } from '@/hooks/useStatusUtils'
import { StatusType } from '@prisma/client'

import TaskTypeIcon from '@/components/TaskTypeSelect/Icon'

function BoardItemCover({ cover }: { cover: string | null }) {
Expand All @@ -18,37 +23,46 @@ function BoardItemCover({ cover }: { cover: string | null }) {
)
}


export default function BoardItem({ data }: { data: ExtendedTask }) {
const { orgID, projectId } = useParams()
const { replace } = useRouter()
const { getStatusTypeByTaskId } = useStatusUtils()
const { getSp } = useUrl()
// return <div className="">{data.title}</div>
const link = `${orgID}/project/${projectId}?mode=${getSp('mode')}&taskId=${
data.id
}`
const isRand = data.id.includes('TASK-ID-RAND')
const link = `${orgID}/project/${projectId}?mode=${getSp('mode')}&taskId=${data.id
}`
const includeRandID = data.id.includes('TASK-ID-RAND')
const dateClasses: string[] = []
const taskStatusType = getStatusTypeByTaskId(data.id)
const { dueDate } = data

if (dueDate && taskStatusType !== StatusType.DONE && differenceInDays(new Date(dueDate), new Date()) < 0) {
dateClasses.push('text-red-400')
}

return (
<div
className="board-item relative"
onClick={() => {
if (isRand) {
if (includeRandID) {
messageWarning('This task has been creating by server !')
return
}
replace(link)
}}>
<BoardItemCover cover={data.cover} />
<PriorityText type={data.priority || 'LOW'} />
<Loading.Absolute enabled={isRand} />
<Loading.Absolute enabled={includeRandID} />

<h2 className="text-sm dark:text-gray-400 text-gray-600 whitespace-normal cursor-pointer space-x-1">
<span>{data.title}</span>
<TaskTypeIcon size="sm" type={data.type || ''} />

</h2>

<div className="board-item-action">
{data.dueDate ? (
<span className="text-gray-400 text-xs">
<span className={`text-gray-400 text-xs ${dateClasses.join(' ')}`}>
{dateFormat(new Date(data.dueDate), 'PP')}
</span>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { genAWeekOfDate, genCalendarArr } from '@shared/libs'
import CalMonthCell from './CalMonthCell'
import { DragDropContext } from 'react-beautiful-dnd'
import useCalendarAction from './useCalendarAction'
import { useTaskStore } from '@/store/task'
import { Loading } from '@shared/ui'
import { ICalendarView } from './context'
import CalendarHeader from './CalendarHeader'

Expand All @@ -14,13 +12,10 @@ interface ICalMonthContainerProps {

export default function CalMonthContainer({ date, type }: ICalMonthContainerProps) {
const { onDragEnd } = useCalendarAction()
const { taskLoading } = useTaskStore()

// let calendars:Date[][] = genCalendarArr(date)
let calendars: Date[][] = []
let isWeekView = false

// let calendars: Date[][]
if (type === ICalendarView.WEEK) {
isWeekView = true
const d = new Date()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface ICalMonthTaskProps {
assigneeId: string
taskStatusId: string
index: number
classes?: Array<string>
}

export default function CalMonthTask({
Expand All @@ -26,13 +27,17 @@ export default function CalMonthTask({
id,
title,
assigneeId,
taskStatusId
taskStatusId,
classes = []
}: ICalMonthTaskProps) {
const { filter } = useTaskFilterContext()
const { statusIds: filterStatusIds } = filter
const { color } = useStatusData(taskStatusId || '')
const { calendarView } = useCalendarContext()

const taskClasses = ['calendar-task-item']
classes?.length && taskClasses.push(...classes)

const view = () => (
<Link href={link}>
<Draggable draggableId={id} index={index}>
Expand All @@ -42,7 +47,7 @@ export default function CalMonthTask({
{...provided.dragHandleProps}
ref={provided.innerRef}
className="relative">
<div className="calendar-task-item">
<div className={taskClasses.join(' ')}>
{calendarView === ICalendarView.WEEK ? (
<CalTaskInWeek
type={taskType}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import Link from 'next/link'
import { useParams } from 'next/navigation'
import { useUrl } from '@/hooks/useUrl'
import { useTaskFilter } from '@/features/TaskFilter/context'
import differenceInDays from 'date-fns/differenceInDays'
import { TaskType } from '@prisma/client'


let index = 0

export default function CalMonthTaskList({ day }: { day: Date }) {
Expand All @@ -16,8 +18,13 @@ export default function CalMonthTaskList({ day }: { day: Date }) {

const mode = getSp('mode')

const dateClasses: string[] = []
if (day && differenceInDays(new Date(day), new Date()) < 0) {
dateClasses.push('overdue-task')
}

return (
<div className="calendar-month-tasks ">
<div className='calendar-month-tasks'>
{tasks.map(task => {
if (!task.dueDate) return null
const dueDate = new Date(task.dueDate)
Expand All @@ -35,9 +42,8 @@ export default function CalMonthTaskList({ day }: { day: Date }) {

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

return (
<CalMonthTask
Expand All @@ -50,6 +56,7 @@ export default function CalMonthTaskList({ day }: { day: Date }) {
id={task.id}
assigneeId={task.assigneeIds[0]}
taskStatusId={task.taskStatusId || ''}
classes={dateClasses}
/>
)
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
}

.calendar-day.today .day-display {
@apply text-indigo-500 font-bold;
@apply dark:text-indigo-400;
@apply text-indigo-500 bg-indigo-100 font-bold;
@apply dark:text-indigo-900 dark:bg-indigo-400;
}

.calendar-month-tasks {
Expand All @@ -65,6 +65,10 @@
@apply hidden;
}

.overdue-task {
@apply text-red-500;
}

.week-view .calendar-task-item {
@apply whitespace-pre-wrap;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/ui-app/app/[orgID]/project/[projectId]/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@
@apply text-xs sm:text-sm;
}

.task-date.overdue .form-input {
@apply text-red-400
}

.project-member-permission {
@apply w-[100px];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ProgressBar from '@/components/ProgressBar'
import { useParams, useRouter } from 'next/navigation'
import { useUrl } from '@/hooks/useUrl'
import { Loading, messageWarning } from '@shared/ui'
import differenceInDays from 'date-fns/differenceInDays'
import TaskTypeCell from './TaskTypeCell'

export default function ListRow({ task }: { task: ExtendedTask }) {
Expand All @@ -19,6 +20,12 @@ export default function ListRow({ task }: { task: ExtendedTask }) {
const { getSp } = useUrl()
const isRandomId = task.id.includes('TASK-ID-RAND')

const dateClasses: string[] = []
const { dueDate } = task
if (dueDate && differenceInDays(new Date(dueDate), new Date()) < 0) {
dateClasses.push('text-red-500')
}

return (
<div
className="px-3 py-2 text-sm sm:flex items-center justify-between group relative"
Expand Down Expand Up @@ -71,7 +78,8 @@ export default function ListRow({ task }: { task: ExtendedTask }) {
<ListCell className="hidden sm:w-[50px] sm:block">
<TaskPoint taskId={task.id} value={task.taskPoint} />
</ListCell>
<ListCell className="ml-6 sm:ml-0 sm:w-[110px]">
<ListCell
className={`ml-6 sm:ml-0 sm:w-[110px] ${dateClasses.join(' ')}`}>
<TaskDate
toNow={true}
taskId={task.id}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { DatePickerBorderless } from '@shared/ui'
import { useEffect, useState } from 'react'
import { useTaskUpdate } from './useTaskUpdate'
import { differenceInDays } from 'date-fns'
import { useStatusUtils } from '@/hooks/useStatusUtils'
import { StatusType } from '@prisma/client'

export default function TaskDate({
date,
Expand All @@ -14,6 +17,7 @@ export default function TaskDate({
toNow?: boolean
}) {
const [value, setValue] = useState(date)
const { getStatusTypeByTaskId } = useStatusUtils()
const { updateTaskData } = useTaskUpdate()

useEffect(() => {
Expand All @@ -32,8 +36,17 @@ export default function TaskDate({
})
}

const taskStatusType = getStatusTypeByTaskId(taskId)
const classes: string[] = []

className && classes.push(className)

if (date && taskStatusType !== StatusType.DONE && differenceInDays(new Date(date), new Date()) < 0) {
classes.push('overdue')
}

return (
<div className={`task-date ${className}`}>
<div className={`task-date ${classes.join(' ')}`}>
<DatePickerBorderless
toNow={toNow}
value={value || undefined}
Expand Down
3 changes: 3 additions & 0 deletions packages/ui-app/app/_features/ProjectContainer/useGetTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { useParams } from 'next/navigation'
import { messageError } from '@shared/ui'
import localforage from 'localforage'
import useTaskFilterContext from '../TaskFilter/useTaskFilterContext'
import differenceInDays from 'date-fns/differenceInDays'
import { Task } from '@prisma/client'

export default function useGetTask() {
const { projectId } = useParams()
Expand Down Expand Up @@ -90,6 +92,7 @@ export default function useGetTask() {
setTimeout(() => {
addAllTasks(data)
}, 300)

})
.finally(() => {
setTaskLoading(false)
Expand Down
2 changes: 0 additions & 2 deletions packages/ui-app/app/_features/TaskFilter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ export default function TaskFilter({
}, 250) as unknown as number
}, [txt])

console.log('isCalendar', isCalendarMode)

return (
<div className="task-filter">
<div className="flex items-center gap-2">
Expand Down
44 changes: 44 additions & 0 deletions packages/ui-app/app/_hooks/useStatusUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useProjectStatusStore } from "@/store/status"
import { useTaskStore } from "@/store/task"
import { StatusType } from "@prisma/client"
import { useMemo } from "react"

export const useStatusUtils = () => {

const { statuses } = useProjectStatusStore()
const { tasks } = useTaskStore()

const doneStatus = useMemo(() => {
const doneIds: string[] = []
statuses.forEach(stt => {
if (stt.type === StatusType.DONE) {
doneIds.push(stt.id)
}
})

return doneIds
}, [statuses.toString()])


const isDoneStatus = (statusId: string) => {
return doneStatus.includes(statusId)
}

const getStatusTypeByTaskId = (taskId: string) => {
const found = tasks.find(t => t.id === taskId)

if (!found) return StatusType.TODO

const foundStatus = statuses.find(stt => stt.id === found.taskStatusId)


if (!foundStatus) return StatusType.TODO

return foundStatus.type
}

return {
isDoneStatus,
getStatusTypeByTaskId,
}
}
Loading

0 comments on commit 4506c63

Please sign in to comment.