- {taskLoading || groupByLoading ? (
+ {taskLoading ? (
) : null}
diff --git a/packages/ui-app/app/[orgID]/project/[projectId]/views/TaskCheckAll.tsx b/packages/ui-app/app/[orgID]/project/[projectId]/views/TaskCheckAll.tsx
index 5fdff0e5..3c7d47db 100644
--- a/packages/ui-app/app/[orgID]/project/[projectId]/views/TaskCheckAll.tsx
+++ b/packages/ui-app/app/[orgID]/project/[projectId]/views/TaskCheckAll.tsx
@@ -1,4 +1,5 @@
import { useTaskFilter } from '@/features/TaskFilter/context'
+import useTaskFilterContext from '@/features/TaskFilter/useTaskFilterContext'
import { useTaskStore } from '@/store/task'
import { Form } from '@shared/ui'
import { useEffect, useMemo, useState } from 'react'
@@ -8,7 +9,7 @@ export default function TaskCheckAll({ groupId }: { groupId: string }) {
const { tasks, selected, taskLoading, toggleMultipleSelected } =
useTaskStore()
const { groupBy, isGroupbyStatus, isGroupbyAssignee, isGroupbyPriority } =
- useTaskFilter()
+ useTaskFilterContext()
const taskIds = useMemo(() => {
const ids: string[] = []
diff --git a/packages/ui-app/app/_features/Project/Vision/VisionMonthNavigator.tsx b/packages/ui-app/app/_features/Project/Vision/VisionMonthNavigator.tsx
index 605f9b5e..a871e47e 100644
--- a/packages/ui-app/app/_features/Project/Vision/VisionMonthNavigator.tsx
+++ b/packages/ui-app/app/_features/Project/Vision/VisionMonthNavigator.tsx
@@ -1,9 +1,10 @@
import ListPreset from '@/components/ListPreset'
import { useTaskFilter } from '@/features/TaskFilter/context'
import { useVisionContext } from './context'
+import useTaskFilterContext from '@/features/TaskFilter/useTaskFilterContext'
export default function VisionMonthNavigator() {
- const { setDateRangeByMonth } = useTaskFilter()
+ const { setDateRangeByMonth } = useTaskFilterContext()
const { filter, setFilter } = useVisionContext()
const { month } = filter
const months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
diff --git a/packages/ui-app/app/_features/ProjectContainer/index.tsx b/packages/ui-app/app/_features/ProjectContainer/index.tsx
index 9c151d7a..4d13e1f9 100644
--- a/packages/ui-app/app/_features/ProjectContainer/index.tsx
+++ b/packages/ui-app/app/_features/ProjectContainer/index.tsx
@@ -15,6 +15,7 @@ import { useGetMembers } from './useGetMembers'
import useGetProjectPoint from './useGetProjectPoint'
import { useUser } from '@goalie/nextjs'
import { useGenTaskMappingObject } from '@/hooks/useGenTaskMappingObject'
+import useUpdateGroupbyItem from '../TaskFilter/useUpdateGroupbyItem'
export default function ProjectContainer() {
const { projectId, orgID } = useParams()
@@ -22,6 +23,7 @@ export default function ProjectContainer() {
const { getSp } = useUrl()
const { user } = useUser()
+ useUpdateGroupbyItem()
useTodoFilter()
useGetProjectStatus()
useGetTask()
diff --git a/packages/ui-app/app/_features/ProjectContainer/useGetTask.ts b/packages/ui-app/app/_features/ProjectContainer/useGetTask.ts
index 435a1c71..c039b47f 100644
--- a/packages/ui-app/app/_features/ProjectContainer/useGetTask.ts
+++ b/packages/ui-app/app/_features/ProjectContainer/useGetTask.ts
@@ -1,18 +1,19 @@
-import { useEffect, useState } from 'react'
-import { useTaskFilter } from '../TaskFilter/context'
+import { useEffect } from 'react'
import { extractDueDate } from '@shared/libs'
import { ExtendedTask, useTaskStore } from '@/store/task'
import { taskGetByCond } from '@/services/task'
import { useParams } from 'next/navigation'
import { messageError } from '@shared/ui'
import localforage from 'localforage'
+import useTaskFilterContext from '../TaskFilter/useTaskFilterContext'
export default function useGetTask() {
const { projectId } = useParams()
const { addAllTasks, setTaskLoading } = useTaskStore()
- const { filter } = useTaskFilter()
+ const { filter } = useTaskFilterContext()
- const { groupBy, status, ...filterWithoutGroupBy } = filter
+ const { groupBy, status, statusIds, ...filterWithoutGroupBy } = filter
+ // const { groupBy, status,...filterWithoutGroupBy } = filter
const key = `TASKLIST_${projectId}`
const getAssigneeIds = (assigneeIds: string[]) => {
@@ -27,6 +28,7 @@ export default function useGetTask() {
.getItem(key)
.then(val => {
if (val) {
+ console.log('appied caches from indexdb')
addAllTasks(val as ExtendedTask[])
}
})
@@ -60,7 +62,7 @@ export default function useGetTask() {
})
setTaskLoading(true)
- console.log('before getting task =======================', point)
+
taskGetByCond(
{
title: term || undefined,
@@ -75,7 +77,8 @@ export default function useGetTask() {
)
.then(res => {
const { data, status, error } = res.data
- console.log('fetch task data', data)
+ console.log('fetched task from server')
+
if (status !== 200) {
addAllTasks([])
localforage.removeItem(key)
@@ -85,7 +88,6 @@ export default function useGetTask() {
localforage.setItem(key, data)
setTimeout(() => {
- console.log('update all task', data)
addAllTasks(data)
}, 300)
})
diff --git a/packages/ui-app/app/_features/ProjectView/ProjectViewModalForm.tsx b/packages/ui-app/app/_features/ProjectView/ProjectViewModalForm.tsx
index 2412e76e..86d398a3 100644
--- a/packages/ui-app/app/_features/ProjectView/ProjectViewModalForm.tsx
+++ b/packages/ui-app/app/_features/ProjectView/ProjectViewModalForm.tsx
@@ -52,6 +52,8 @@ export default function ProjectViewModalForm({
})
}
+ console.log('type', type)
+
return (
diff --git a/packages/ui-app/app/_features/ProjectView/index.tsx b/packages/ui-app/app/_features/ProjectView/index.tsx
index 3834ff87..5d94a2b0 100644
--- a/packages/ui-app/app/_features/ProjectView/index.tsx
+++ b/packages/ui-app/app/_features/ProjectView/index.tsx
@@ -11,29 +11,6 @@ import DynamicIcon from '@/components/DynamicIcon'
import HasRole from '../UserPermission/HasRole'
import useSetViewFilter from './useSetViewFilter'
-// function ProjectViewItem({view}: {view: }) {
-// const clickOnView = (name: string) => {
-// push(`${params.orgID}/project/${params.projectId}?mode=${name}`)
-// }
-// return
clickOnView(view.id)}
-// className={`project-view-item group relative ${active ? 'active' : ''
-// }`}
-// key={index}>
-// {icon ? (
-//
-// ) : (
-//
-// )}
-//
{view.name}
-//
-//
-// }
-
export default function ProjectView() {
const searchParams = useSearchParams()
const { push } = useRouter()
diff --git a/packages/ui-app/app/_features/ProjectView/useSetViewFilter.ts b/packages/ui-app/app/_features/ProjectView/useSetViewFilter.ts
index 4b1b4f6f..b9450bc7 100644
--- a/packages/ui-app/app/_features/ProjectView/useSetViewFilter.ts
+++ b/packages/ui-app/app/_features/ProjectView/useSetViewFilter.ts
@@ -1,13 +1,13 @@
-import { useDebounce } from "@/hooks/useDebounce"
-import { useSearchParams } from "next/navigation"
-import { useProjectViewList } from "./useProjectViewList"
-import { useTaskFilter } from "../TaskFilter/context"
-import { IBoardFilter } from "./context"
+import { useDebounce } from '@/hooks/useDebounce'
+import { useSearchParams } from 'next/navigation'
+import { useProjectViewList } from './useProjectViewList'
+import { IBoardFilter } from './context'
+import useTaskFilterContext from '../TaskFilter/useTaskFilterContext'
export default function useSetViewFilter() {
const searchParams = useSearchParams()
const { views } = useProjectViewList()
- const { setFilter, setDefaultFilter } = useTaskFilter()
+ const { setFilter, setDefaultFilter } = useTaskFilterContext()
const mode = searchParams.get('mode')
// update task filter once user change to another view
diff --git a/packages/ui-app/app/_features/ProjectViewFilter/BoardFilter.tsx b/packages/ui-app/app/_features/ProjectViewFilter/BoardFilter.tsx
index 50252469..1068e7df 100644
--- a/packages/ui-app/app/_features/ProjectViewFilter/BoardFilter.tsx
+++ b/packages/ui-app/app/_features/ProjectViewFilter/BoardFilter.tsx
@@ -1,31 +1,35 @@
-import { ProjectViewType } from "@prisma/client";
-import { Button } from "@shared/ui";
-import FilterForm from "./FilterForm";
+import { ProjectViewType } from '@prisma/client'
+import { Button } from '@shared/ui'
+import FilterForm from './FilterForm'
-export default function ProjectViewFilterByBoard({ type, desc, onAdd }: {
+export default function ProjectViewFilterByBoard({
+ type,
+ desc,
+ onAdd
+}: {
type: ProjectViewType
desc: string
onAdd: () => void
}) {
if (type !== ProjectViewType.BOARD) return null
- return <>
-
-
Board
-
{desc}
+ return (
+ <>
+
+
>
+ >
+ )
}
diff --git a/packages/ui-app/app/_features/ProjectViewFilter/FilterForm.tsx b/packages/ui-app/app/_features/ProjectViewFilter/FilterForm.tsx
index a3714278..a0c6d47b 100644
--- a/packages/ui-app/app/_features/ProjectViewFilter/FilterForm.tsx
+++ b/packages/ui-app/app/_features/ProjectViewFilter/FilterForm.tsx
@@ -1,103 +1,113 @@
-import ListPreset from "@/components/ListPreset";
-import PointSelect from "@/components/PointSelect";
-import PrioritySelect from "@/components/PrioritySelect";
-import { Form } from "@shared/ui";
-import { ETaskFilterGroupByType } from "../TaskFilter/context";
-import { useProjectViewContext } from "../ProjectView/context";
-import StatusSelectMultiple from "@/components/StatusSelectMultiple";
-import { ProjectViewType } from "@prisma/client";
+import ListPreset from '@/components/ListPreset'
+import PointSelect from '@/components/PointSelect'
+import PrioritySelect from '@/components/PrioritySelect'
+import { Form } from '@shared/ui'
+import { ETaskFilterGroupByType } from '../TaskFilter/context'
+import { useProjectViewContext } from '../ProjectView/context'
+import StatusSelectMultiple from '@/components/StatusSelectMultiple'
+import { ProjectViewType } from '@prisma/client'
export default function FilterForm({ type }: { type?: ProjectViewType }) {
-
- const { customView, setCustomView, filter, setFilterValue } = useProjectViewContext()
+ const { customView, setCustomView, filter, setFilterValue } =
+ useProjectViewContext()
const hidden = customView ? '' : 'hidden'
const { date, point, priority, groupBy, statusIds } = filter
- return <>
-
-
setCustomView(stt)} />
- Add some filter to make an unique view.
-
-
-
-
-
{
- setFilterValue('date', val)
- }}
- width={200}
- options={[
- { id: 'today', title: '📆 Today' },
- { id: 'yesterday', title: '📆 Yesterday' },
- { id: 'tomorrow', title: '📆 Tomorrow' },
- { id: 'prev-week', title: '📆 Prev week' },
- { id: 'prev-month', title: '📆 Prev month' },
- { id: 'this-week', title: '📆 This week' },
- { id: 'this-month', title: '📆 This month' },
- { id: 'next-week', title: '📆 Next week' },
- { id: 'next-month', title: '📆 Next month' },
- { id: 'not-set', title: '📆 Not set' },
- ]}
- />
+ console.log('type', type)
-
+
+
setCustomView(stt)}
+ />
+
+ Add some filter to make an unique view.
+
+
- value={point}
- onChange={val => {
- setFilterValue('point', val)
- }}
- zero={true}
- infinite={true} />
+
+
{
+ setFilterValue('date', val)
+ }}
+ width={200}
+ options={[
+ { id: 'today', title: '📆 Today' },
+ { id: 'yesterday', title: '📆 Yesterday' },
+ { id: 'tomorrow', title: '📆 Tomorrow' },
+ { id: 'prev-week', title: '📆 Prev week' },
+ { id: 'prev-month', title: '📆 Prev month' },
+ { id: 'this-week', title: '📆 This week' },
+ { id: 'this-month', title: '📆 This month' },
+ { id: 'next-week', title: '📆 Next week' },
+ { id: 'next-month', title: '📆 Next month' },
+ { id: 'not-set', title: '📆 Not set' }
+ ]}
+ />
- {
- setFilterValue('priority', val)
- }}
- />
- {type === ProjectViewType.CALENDAR ?
- {
- setFilterValue('statusIds', val)
+ {
+ setFilterValue('point', val)
+ }}
+ zero={true}
+ infinite={true}
+ />
- }} />
- : null}
-
+ {
+ setFilterValue('priority', val)
+ }}
+ />
+ {type === ProjectViewType.CALENDAR || type === ProjectViewType.BOARD ? (
+ {
+ setFilterValue('statusIds', val)
+ }}
+ />
+ ) : null}
+
-
-
Group this by.
-
{
- setFilterValue('groupBy', val as ETaskFilterGroupByType)
- }}
- className="w-[150px] mr-1"
- width={150}
- options={[
- {
- id: ETaskFilterGroupByType.STATUS,
- title: 'Status',
- icon: '🚦'
- },
- {
- id: ETaskFilterGroupByType.ASSIGNEE,
- title: 'Assignees',
- icon: '🤓'
- },
- {
- id: ETaskFilterGroupByType.PRIORITY,
- title: 'Priority',
- icon: '🚩'
- }
- // { id: ETaskFilterGroupByType.WEEK, title: 'Week', icon: '📅' }
- ]}
- />
-
- >
+
+
Group this by.
+
{
+ setFilterValue('groupBy', val as ETaskFilterGroupByType)
+ }}
+ className="w-[150px] mr-1"
+ width={150}
+ options={[
+ {
+ id: ETaskFilterGroupByType.STATUS,
+ title: 'Status',
+ icon: '🚦'
+ },
+ {
+ id: ETaskFilterGroupByType.ASSIGNEE,
+ title: 'Assignees',
+ icon: '🤓'
+ },
+ {
+ id: ETaskFilterGroupByType.PRIORITY,
+ title: 'Priority',
+ icon: '🚩'
+ }
+ // { id: ETaskFilterGroupByType.WEEK, title: 'Week', icon: '📅' }
+ ]}
+ />
+
+ >
+ )
}
diff --git a/packages/ui-app/app/_features/Report/ReportContent.tsx b/packages/ui-app/app/_features/Report/ReportContent.tsx
index fe005c64..d878eabb 100644
--- a/packages/ui-app/app/_features/Report/ReportContent.tsx
+++ b/packages/ui-app/app/_features/Report/ReportContent.tsx
@@ -5,13 +5,13 @@ import { useOrgMemberStore } from '@/store/orgMember'
import { useProjectStore } from '@/store/project'
import { extractDueDate } from '@shared/libs'
import { useEffect, useState } from 'react'
-import { useTaskFilter } from '../TaskFilter/context'
import { ReportProvider } from './context'
import { Task } from '@prisma/client'
import ReportLayout from './ReportLayout'
+import useTaskFilterContext from '../TaskFilter/useTaskFilterContext'
export default function ReportContent() {
- const { filter } = useTaskFilter()
+ const { filter } = useTaskFilterContext()
const { projects } = useProjectStore()
const { orgMembers } = useOrgMemberStore()
const [tasks, setTasks] = useState
([])
diff --git a/packages/ui-app/app/_features/TaskFilter/CalendarModeFilter.tsx b/packages/ui-app/app/_features/TaskFilter/CalendarModeFilter.tsx
index 42940015..d2913444 100644
--- a/packages/ui-app/app/_features/TaskFilter/CalendarModeFilter.tsx
+++ b/packages/ui-app/app/_features/TaskFilter/CalendarModeFilter.tsx
@@ -3,11 +3,15 @@ import { useSearchParams } from 'next/navigation'
import { useEffect } from 'react'
import { HiChevronLeft, HiChevronRight } from 'react-icons/hi2'
import { useTaskFilter } from './context'
-import { ICalendarView, useCalendarContext } from '../../[orgID]/project/[projectId]/calendar/context'
+import {
+ ICalendarView,
+ useCalendarContext
+} from '../../[orgID]/project/[projectId]/calendar/context'
import { getMonthList } from '@shared/libs'
+import useTaskFilterContext from './useTaskFilterContext'
const CalendarFilter = () => {
- const { filter, setFilterValue } = useTaskFilter()
+ const { filter, setFilterValue } = useTaskFilterContext()
const { month, setMonth } = useCalendarContext()
const search = useSearchParams()
const { setCalendarView } = useCalendarContext()
@@ -36,20 +40,19 @@ const CalendarFilter = () => {
return (
<>
-
-
+
{
setCalendarView(val as ICalendarView)
}}
width={150}
options={[
{ id: ICalendarView.WEEK, title: 'Week view' },
- { id: ICalendarView.MONTH, title: 'Month view' },
- ]} />
+ { id: ICalendarView.MONTH, title: 'Month view' }
+ ]}
+ />
{/* */}
{/* {
{/* { id: 'ALL', title: 'All Task' }, */}
{/* ]} /> */}
-
+
>
}
-const TaskFilterContext = createContext({
+export const TaskFilterContext = createContext({
groupByItems: [],
groupByLoading: false,
setGroupbyItems: () => {
@@ -196,7 +196,6 @@ export const useTaskFilter = () => {
}
})
-
if (noneItems.length) {
groupStatuses.push({
id: 'NONE',
@@ -248,7 +247,7 @@ export const useTaskFilter = () => {
tasks.forEach(t => {
if (ignored.includes(t.id)) return
- if (!t.assigneeIds.length) {
+ if (!t.assigneeIds.length && !taskWithoutAssignee.includes(t.id)) {
taskWithoutAssignee.push(t.id)
return
}
@@ -356,6 +355,7 @@ export const useTaskFilter = () => {
timeout = setTimeout(() => {
if (oldGroupByType.current !== filter.groupBy) {
+ console.log('called groupby')
updateGroupbyItems()
oldGroupByType.current = filter.groupBy
}
diff --git a/packages/ui-app/app/_features/TaskFilter/index.tsx b/packages/ui-app/app/_features/TaskFilter/index.tsx
index 755d312b..0a0b2dac 100644
--- a/packages/ui-app/app/_features/TaskFilter/index.tsx
+++ b/packages/ui-app/app/_features/TaskFilter/index.tsx
@@ -14,6 +14,7 @@ import { useProjectViewList } from '../ProjectView/useProjectViewList'
import { ProjectViewType } from '@prisma/client'
import StatusSelect from '@/components/StatusSelect'
import StatusSelectMultiple from '@/components/StatusSelectMultiple'
+import useTaskFilterContext from './useTaskFilterContext'
let timeout = 0
interface ITaskFilterProps {
@@ -29,7 +30,7 @@ export default function TaskFilter({
importEnable = true
}: ITaskFilterProps) {
const [txt, setTxt] = useState('')
- const { filter, setFilterValue, updateGroupByFilter } = useTaskFilter()
+ const { filter, setFilterValue, updateGroupByFilter } = useTaskFilterContext()
const { currentViewType } = useProjectViewList()
const {
@@ -45,6 +46,10 @@ export default function TaskFilter({
const isDateRange = date === 'date-range'
const isCalendarMode = currentViewType === ProjectViewType.CALENDAR
+ const isTeamMode = currentViewType === ProjectViewType.TEAM
+ const isShowStatusFilter =
+ currentViewType === ProjectViewType.CALENDAR ||
+ currentViewType === ProjectViewType.BOARD
const showOperator = ['this-month', 'this-week', 'today']
useEffect(() => {
@@ -53,7 +58,6 @@ export default function TaskFilter({
}
timeout = setTimeout(() => {
-
setFilterValue('term', txt)
}, 250) as unknown as number
}, [txt])
@@ -146,9 +150,15 @@ export default function TaskFilter({
/>
) : null}
- {isCalendarMode ? {
- setFilterValue('statusIds', val)
- }} /> : null}
+ {isShowStatusFilter ? (
+ {
+ setFilterValue('statusIds', val)
+ }}
+ />
+ ) : null}
) : null}
- {isCalendarMode ? null : (
+ {isCalendarMode || isTeamMode ? null : (
{
diff --git a/packages/ui-app/app/_features/TaskFilter/useTaskFilterContext.ts b/packages/ui-app/app/_features/TaskFilter/useTaskFilterContext.ts
new file mode 100644
index 00000000..762ec527
--- /dev/null
+++ b/packages/ui-app/app/_features/TaskFilter/useTaskFilterContext.ts
@@ -0,0 +1,120 @@
+import { useContext } from 'react'
+import {
+ ETaskFilterGroupByType,
+ ITaskFilterFields,
+ TaskFilterContext
+} from './context'
+import { getLastDateOfMonth } from '@shared/libs'
+
+const d = new Date()
+const firstDate = new Date(d.getFullYear(), d.getMonth(), 1)
+const lastDate = getLastDateOfMonth(new Date())
+
+const defaultFilter: ITaskFilterFields = {
+ term: '',
+ groupBy: ETaskFilterGroupByType.STATUS,
+ dateOperator: '=',
+ date: 'this-month',
+ startDate: firstDate,
+ endDate: lastDate,
+ point: '-1',
+ priority: 'ALL',
+ assigneeIds: ['ALL'],
+ statusIds: ['ALL'],
+ status: 'ALL'
+}
+
+export default function useTaskFilterContext() {
+ const {
+ filter,
+ setFilter,
+ groupByItems,
+ setGroupbyItems,
+ groupByLoading,
+ setGroupbyLoading
+ } = useContext(TaskFilterContext)
+
+ const setFilterValue = (
+ name: keyof ITaskFilterFields,
+ val: string | string[] | Date | ETaskFilterGroupByType
+ ) => {
+ setFilter(filter => ({ ...filter, [name]: val }))
+ }
+
+ const setDefaultFilter = () => {
+ setFilter(defaultFilter)
+ }
+
+ const updateGroupByFilter = (val: ETaskFilterGroupByType) => {
+ if (val === filter.groupBy) return
+ setGroupbyLoading(true)
+ setFilterValue('groupBy', val)
+ }
+
+ const setDateRangeByMonth = (month: string) => {
+ const today = new Date()
+ const lastDayOfMonth = new Date(today.getFullYear(), +month + 1, 0)
+ const startDayOfMonth = new Date(today.getFullYear(), +month, 1)
+
+ setFilter(prev => ({
+ ...prev,
+ date: 'date-range',
+ startDate: startDayOfMonth,
+ endDate: lastDayOfMonth
+ }))
+ }
+
+ const swapGroupItemOrder = (sourceId: number, destId: number) => {
+ const cloned = structuredClone(groupByItems)
+
+ const destItem = cloned[sourceId]
+ cloned.splice(sourceId, 1)
+ cloned.splice(destId, 0, destItem)
+
+ setGroupbyItems(cloned)
+ }
+
+ const swapTaskOrder = (
+ dropId: string,
+ sourceIndex: number,
+ destIndex: number
+ ) => {
+ const cloned = structuredClone(groupByItems)
+ const groupItem = cloned.find(c => c.id === dropId)
+
+ if (!groupItem) return
+
+ const items = groupItem.items
+
+ // const destItem = items[sourceIndex]
+ // items.splice(sourceIndex, 1)
+ // items.splice(destIndex, 0, destItem)
+
+ const [removed] = items.splice(sourceIndex, 1)
+ items.splice(destIndex, 0, removed)
+
+ setGroupbyItems(cloned)
+ }
+
+ const isGroupbyStatus = filter.groupBy === ETaskFilterGroupByType.STATUS
+ const isGroupbyAssignee = filter.groupBy === ETaskFilterGroupByType.ASSIGNEE
+ const isGroupbyPriority = filter.groupBy === ETaskFilterGroupByType.PRIORITY
+
+ return {
+ groupBy: filter.groupBy,
+ groupByLoading,
+ groupByItems,
+ setGroupbyItems,
+ swapTaskOrder,
+ swapGroupItemOrder,
+ filter,
+ setFilter,
+ setDefaultFilter,
+ setFilterValue,
+ isGroupbyStatus,
+ updateGroupByFilter,
+ setDateRangeByMonth,
+ isGroupbyAssignee,
+ isGroupbyPriority
+ }
+}
diff --git a/packages/ui-app/app/_features/TaskFilter/useTodoFilter.ts b/packages/ui-app/app/_features/TaskFilter/useTodoFilter.ts
index 0242edfa..1d088b50 100644
--- a/packages/ui-app/app/_features/TaskFilter/useTodoFilter.ts
+++ b/packages/ui-app/app/_features/TaskFilter/useTodoFilter.ts
@@ -1,11 +1,11 @@
import { useSearchParams } from 'next/navigation'
-import { useTaskFilter } from './context'
import { useUser } from '@goalie/nextjs'
import { useDebounce } from '@/hooks/useDebounce'
+import useTaskFilterContext from './useTaskFilterContext'
export const useTodoFilter = () => {
- const { setFilter } = useTaskFilter()
+ const { setFilter } = useTaskFilterContext()
const sp = useSearchParams()
const { user } = useUser()
diff --git a/packages/ui-app/app/_features/TaskFilter/useUpdateGroupbyItem.ts b/packages/ui-app/app/_features/TaskFilter/useUpdateGroupbyItem.ts
new file mode 100644
index 00000000..feda2ef7
--- /dev/null
+++ b/packages/ui-app/app/_features/TaskFilter/useUpdateGroupbyItem.ts
@@ -0,0 +1,245 @@
+import { TaskPriority } from '@prisma/client'
+import {
+ ETaskFilterGroupByType,
+ ITaskFilterGroupbyItem,
+ TaskFilterContext
+} from './context'
+import { useProjectStatusStore } from '@/store/status'
+import { useMemberStore } from '@/store/member'
+import { useTaskStore } from '@/store/task'
+import { useParams } from 'next/navigation'
+import { useContext, useEffect, useRef } from 'react'
+
+let timeout = 0
+export default function useUpdateGroupbyItem() {
+ const { statuses } = useProjectStatusStore()
+ const { members } = useMemberStore()
+ const { tasks } = useTaskStore()
+ const { projectId } = useParams()
+
+ const oldGroupByType = useRef('')
+ const oldStatusList = useRef(statuses)
+ const oldTaskList = useRef(tasks)
+
+ const { filter, setGroupbyItems, setGroupbyLoading } =
+ useContext(TaskFilterContext)
+
+ const _groupByStatus = (): ITaskFilterGroupbyItem[] => {
+ const ignored: string[] = []
+ const statusIds = statuses.map(s => s.id)
+ const noneItems: string[] = []
+
+ const groupStatuses = statuses.map(stt => {
+ const { id, name, color } = stt
+ const items: string[] = []
+
+ tasks.forEach(t => {
+ if (ignored.includes(t.id)) return
+
+ const { taskStatusId } = t
+
+ if (taskStatusId === id) {
+ items.push(t.id)
+ ignored.push(t.id)
+ return
+ }
+
+ if (!statusIds.includes(taskStatusId || '')) {
+ noneItems.push(t.id)
+ ignored.push(t.id)
+ return
+ }
+
+ if (!taskStatusId || !statusIds.includes(taskStatusId)) {
+ noneItems.push(t.id)
+
+ ignored.push(t.id)
+ }
+ })
+
+ return {
+ id,
+ color,
+ name,
+ items
+ }
+ })
+
+ if (noneItems.length) {
+ groupStatuses.push({
+ id: 'NONE',
+ color: '#cecece',
+ name: 'None',
+ items: noneItems
+ })
+ }
+
+ return groupStatuses
+ }
+
+ const _groupByPriority = (): ITaskFilterGroupbyItem[] => {
+ const priorities = [
+ [TaskPriority.LOW, '#ababab'],
+ [TaskPriority.NORMAL, '#13cfff'],
+ [TaskPriority.HIGH, '#ffce37'],
+ [TaskPriority.URGENT, '#ff1345']
+ ]
+
+ const filteredStatusIds = filter.statusIds
+
+ const ignored: string[] = []
+ return priorities.map(p => {
+ const items: string[] = []
+
+ tasks.forEach(t => {
+ if (ignored.includes(t.id)) return
+
+ if (
+ filteredStatusIds.length &&
+ t.taskStatusId &&
+ !filteredStatusIds.includes('ALL')
+ ) {
+ if (!filteredStatusIds.includes(t.taskStatusId)) {
+ return
+ }
+ }
+
+ if (t.priority === p[0]) {
+ items.push(t.id)
+ ignored.push(t.id)
+ }
+ })
+
+ return {
+ id: p[0],
+ name: p[0],
+ color: p[1],
+ items
+ }
+ })
+ }
+
+ const _groupByAssignee = (): ITaskFilterGroupbyItem[] => {
+ const ignored: string[] = []
+ const taskWithoutAssignee: string[] = []
+ const filteredStatusIds = filter.statusIds
+
+ const newMembers = members.map(mem => {
+ const items: string[] = []
+
+ tasks.forEach(t => {
+ if (ignored.includes(t.id)) return
+
+ if (
+ t.taskStatusId &&
+ filteredStatusIds.length &&
+ !filteredStatusIds.includes('ALL')
+ ) {
+ if (!filteredStatusIds.includes(t.taskStatusId)) {
+ return
+ }
+ }
+
+ if (!t.assigneeIds.length && !taskWithoutAssignee.includes(t.id)) {
+ taskWithoutAssignee.push(t.id)
+ return
+ }
+
+ if (t.assigneeIds.includes(mem.id)) {
+ items.push(t.id)
+ ignored.push(t.id)
+ }
+ })
+ return {
+ id: mem.id,
+ name: mem.name || '',
+ icon: mem.photo || '',
+ items
+ }
+ })
+
+ newMembers.push({
+ id: 'NONE',
+ name: 'Not assigned',
+ icon: '',
+ items: taskWithoutAssignee
+ })
+
+ return newMembers
+ }
+
+ const updateGroupbyItems = () => {
+ let groupItems: ITaskFilterGroupbyItem[] = []
+
+ switch (filter.groupBy) {
+ case ETaskFilterGroupByType.STATUS:
+ groupItems = _groupByStatus()
+ break
+
+ case ETaskFilterGroupByType.PRIORITY:
+ groupItems = _groupByPriority()
+ break
+
+ case ETaskFilterGroupByType.ASSIGNEE:
+ groupItems = _groupByAssignee()
+ break
+ }
+
+ setGroupbyLoading(false)
+ setGroupbyItems(groupItems)
+ }
+
+ // Only update groupByItems as groupBy option changed
+ // keep logic simple
+ useEffect(() => {
+ if (timeout) {
+ clearTimeout(timeout)
+ }
+
+ timeout = setTimeout(() => {
+ if (oldGroupByType.current !== filter.groupBy) {
+ updateGroupbyItems()
+ oldGroupByType.current = filter.groupBy
+ }
+ }, 350) as unknown as number
+ }, [
+ filter.groupBy,
+ JSON.stringify(members),
+ JSON.stringify(statuses),
+ JSON.stringify(tasks)
+ ])
+
+ useEffect(() => {
+ updateGroupbyItems()
+ }, [filter.statusIds.toString()])
+
+ useEffect(() => {
+ if (oldStatusList.current) {
+ const oldStatusArr = oldStatusList.current
+
+ // When page reload, the status list is empty
+ // after a few seconds it will be fetched from servers
+ // so we need to update the groupByItems
+ if (!oldStatusArr.length && statuses.length) {
+ updateGroupbyItems()
+ }
+ }
+ }, [statuses])
+
+ useEffect(() => {
+ if (oldTaskList.current) {
+ const oldTaskArr = oldTaskList.current
+
+ // When page reload, the task list is empty
+ // after a few seconds it will be fetched from servers
+ // so we need to update the groupByItems
+ if (!oldTaskArr.length && tasks.length) {
+ updateGroupbyItems()
+ }
+ }
+ }, [tasks])
+
+ useEffect(() => {
+ updateGroupbyItems()
+ }, [projectId, tasks])
+}
diff --git a/packages/ui-app/services/task.ts b/packages/ui-app/services/task.ts
index c1fe1aab..72f68c0d 100644
--- a/packages/ui-app/services/task.ts
+++ b/packages/ui-app/services/task.ts
@@ -28,7 +28,6 @@ export interface ITaskQuery {
}
export const taskGetByCond = (query: ITaskQuery, signal?: AbortSignal) => {
- console.log('task get by cond', query)
return httpGet(`/api/project/task/query`, {
params: query,
signal: signal
@@ -95,10 +94,7 @@ export const taskMakeCover = (data: {
}
export const serviceTask = {
- reorder: (data: {
- updatedOrder: [string, number][]
- projectId: string
- }) => {
+ reorder: (data: { updatedOrder: [string, number][]; projectId: string }) => {
return httpPost('/api/task/reorder', data)
}
}