refactor: extract shared task page logic into useTaskPage hook
Eliminates code duplication between TaskListPage and TaskBoardPage by extracting common state, effects, and handlers into a custom hook. Also fixes bug where TaskBoardPage's mergeProjects was omitting color/icon. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
119d896a59
commit
5a71aba13f
3 changed files with 182 additions and 230 deletions
152
frontend/src/hooks/useTaskPage.ts
Normal file
152
frontend/src/hooks/useTaskPage.ts
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
import { taskService } from '../services/taskService'
|
||||||
|
import type { Project } from '../services/projectService'
|
||||||
|
import { projectService } from '../services/projectService'
|
||||||
|
import { categoryService } from '../services/categoryService'
|
||||||
|
import { organizationService } from '../services/organizationService'
|
||||||
|
import type { Category } from '../types/category'
|
||||||
|
import type { TaskAssignee, TaskResponse } from '../types/task'
|
||||||
|
import { DEFAULT_TASK_FILTERS, type TaskFilters } from '../components/taskFilters'
|
||||||
|
import { useAuth } from '../contexts/AuthContext'
|
||||||
|
|
||||||
|
interface UseTaskPageOptions {
|
||||||
|
fetchProjects?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UseTaskPageResult {
|
||||||
|
tasks: TaskResponse[]
|
||||||
|
isLoading: boolean
|
||||||
|
projects: Project[]
|
||||||
|
categories: Category[]
|
||||||
|
assignees: TaskAssignee[]
|
||||||
|
filters: TaskFilters
|
||||||
|
currentUserAssigneeId: number | null
|
||||||
|
loadTasks: (filters: TaskFilters, silent?: boolean) => Promise<void>
|
||||||
|
handleFiltersChange: (newFilters: TaskFilters) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeProjects(existing: Project[], tasks: TaskResponse[]) {
|
||||||
|
const byId = new Map(existing.map((project) => [project.id, project]))
|
||||||
|
|
||||||
|
tasks.forEach((task) => {
|
||||||
|
if (task.project) {
|
||||||
|
byId.set(task.project.id, {
|
||||||
|
id: task.project.id,
|
||||||
|
name: task.project.name,
|
||||||
|
color: task.project.color,
|
||||||
|
icon: task.project.icon,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractAssignees(tasks: TaskResponse[]) {
|
||||||
|
const byId = new Map<number, TaskAssignee>()
|
||||||
|
|
||||||
|
tasks.forEach((task) => {
|
||||||
|
if (task.user) {
|
||||||
|
byId.set(task.user.id, task.user)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTaskPage({ fetchProjects = false }: UseTaskPageOptions = {}): UseTaskPageResult {
|
||||||
|
const [tasks, setTasks] = useState<TaskResponse[]>([])
|
||||||
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
const [projects, setProjects] = useState<Project[]>([])
|
||||||
|
const [categories, setCategories] = useState<Category[]>([])
|
||||||
|
const [assignees, setAssignees] = useState<TaskAssignee[]>([])
|
||||||
|
const [filters, setFilters] = useState<TaskFilters>(DEFAULT_TASK_FILTERS)
|
||||||
|
const [currentUserAssigneeId, setCurrentUserAssigneeId] = useState<number | null>(null)
|
||||||
|
const { activeOrg, user } = useAuth()
|
||||||
|
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
|
||||||
|
const loadTasks = async (currentFilters: TaskFilters, silent = false) => {
|
||||||
|
if (!activeOrg) return
|
||||||
|
if (!silent) setIsLoading(true)
|
||||||
|
try {
|
||||||
|
const response = await taskService.getTasks({
|
||||||
|
organizationId: activeOrg.id,
|
||||||
|
text: currentFilters.searchQuery || undefined,
|
||||||
|
projectIds: currentFilters.projectIds.length > 0 ? currentFilters.projectIds : undefined,
|
||||||
|
statuses: currentFilters.statuses.length > 0 ? currentFilters.statuses : undefined,
|
||||||
|
categoryIds: currentFilters.categoryIds.length > 0 ? currentFilters.categoryIds : undefined,
|
||||||
|
userIds: currentFilters.userIds.length > 0 ? currentFilters.userIds : undefined,
|
||||||
|
})
|
||||||
|
setTasks(response)
|
||||||
|
setProjects((current) => mergeProjects(current, response))
|
||||||
|
setAssignees((current) => {
|
||||||
|
const byId = new Map(current.map((assignee) => [assignee.id, assignee]))
|
||||||
|
extractAssignees(response).forEach((assignee) => byId.set(assignee.id, assignee))
|
||||||
|
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao carregar tarefas', error)
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!activeOrg) return
|
||||||
|
|
||||||
|
const init = async () => {
|
||||||
|
setFilters(DEFAULT_TASK_FILTERS)
|
||||||
|
setCategories([])
|
||||||
|
|
||||||
|
const promises: Promise<any>[] = [organizationService.listMembers(activeOrg.id)]
|
||||||
|
|
||||||
|
promises.push(categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {}))
|
||||||
|
|
||||||
|
if (fetchProjects) {
|
||||||
|
promises.push(projectService.listByOrganization(activeOrg.id).then(setProjects).catch(() => {}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const [members] = await Promise.all(promises)
|
||||||
|
|
||||||
|
const assigneesData = members.map((m: any) => ({
|
||||||
|
id: m.userId,
|
||||||
|
name: m.userName,
|
||||||
|
email: m.userEmail,
|
||||||
|
photo: m.userPhoto ?? null,
|
||||||
|
}))
|
||||||
|
setAssignees(assigneesData)
|
||||||
|
|
||||||
|
const currentMember = members.find((m: any) => m.userEmail === user?.email)
|
||||||
|
const userId = currentMember?.userId ?? null
|
||||||
|
setCurrentUserAssigneeId(userId)
|
||||||
|
|
||||||
|
const initialFilters = userId
|
||||||
|
? { ...DEFAULT_TASK_FILTERS, userIds: [userId] }
|
||||||
|
: DEFAULT_TASK_FILTERS
|
||||||
|
setFilters(initialFilters)
|
||||||
|
void loadTasks(initialFilters)
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
}, [activeOrg, user?.email, fetchProjects])
|
||||||
|
|
||||||
|
const handleFiltersChange = (newFilters: TaskFilters) => {
|
||||||
|
setFilters(newFilters)
|
||||||
|
if (debounceRef.current) clearTimeout(debounceRef.current)
|
||||||
|
debounceRef.current = setTimeout(() => {
|
||||||
|
void loadTasks(newFilters)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
tasks,
|
||||||
|
isLoading,
|
||||||
|
projects,
|
||||||
|
categories,
|
||||||
|
assignees,
|
||||||
|
filters,
|
||||||
|
currentUserAssigneeId,
|
||||||
|
loadTasks,
|
||||||
|
handleFiltersChange,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,21 +10,16 @@ import {
|
||||||
Plus,
|
Plus,
|
||||||
XCircle,
|
XCircle,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import { taskService } from '../services/taskService'
|
import { taskService } from '../services/taskService'
|
||||||
import type { Project } from '../services/projectService'
|
import type { TaskStatus } from '../types/task'
|
||||||
import { categoryService } from '../services/categoryService'
|
|
||||||
import { organizationService } from '../services/organizationService'
|
|
||||||
import type { Category } from '../types/category'
|
|
||||||
import { cn } from '../lib/utils'
|
import { cn } from '../lib/utils'
|
||||||
import type { TaskAssignee, TaskResponse, TaskStatus } from '../types/task'
|
|
||||||
import { TaskTimer } from '../components/TaskTimer'
|
import { TaskTimer } from '../components/TaskTimer'
|
||||||
import { TaskFilterBar } from '../components/TaskFilterBar'
|
import { TaskFilterBar } from '../components/TaskFilterBar'
|
||||||
import { DEFAULT_TASK_FILTERS, type TaskFilters } from '../components/taskFilters'
|
|
||||||
import { CategoryBadge } from '../components/CategoryBadge'
|
import { CategoryBadge } from '../components/CategoryBadge'
|
||||||
import { useAuth } from '../contexts/AuthContext'
|
import { useAuth } from '../contexts/AuthContext'
|
||||||
|
import { useTaskPage } from '../hooks/useTaskPage'
|
||||||
|
|
||||||
const COLUMNS: { id: TaskStatus; label: string; icon: LucideIcon; color: string }[] = [
|
const COLUMNS: { id: TaskStatus; label: string; icon: LucideIcon; color: string }[] = [
|
||||||
{ id: 'NOT_STARTED', label: 'Pendente', icon: AlertCircle, color: 'text-text-muted' },
|
{ id: 'NOT_STARTED', label: 'Pendente', icon: AlertCircle, color: 'text-text-muted' },
|
||||||
|
|
@ -33,111 +28,21 @@ const COLUMNS: { id: TaskStatus; label: string; icon: LucideIcon; color: string
|
||||||
{ id: 'CANCELED', label: 'Cancelada', icon: XCircle, color: 'text-danger' },
|
{ id: 'CANCELED', label: 'Cancelada', icon: XCircle, color: 'text-danger' },
|
||||||
]
|
]
|
||||||
|
|
||||||
function mergeProjects(existing: Project[], tasks: TaskResponse[]) {
|
|
||||||
const byId = new Map(existing.map((project) => [project.id, project]))
|
|
||||||
|
|
||||||
tasks.forEach((task) => {
|
|
||||||
if (task.project) {
|
|
||||||
byId.set(task.project.id, { id: task.project.id, name: task.project.name })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractAssignees(tasks: TaskResponse[]) {
|
|
||||||
const byId = new Map<number, TaskAssignee>()
|
|
||||||
|
|
||||||
tasks.forEach((task) => {
|
|
||||||
if (task.user) {
|
|
||||||
byId.set(task.user.id, task.user)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TaskBoardPage() {
|
export function TaskBoardPage() {
|
||||||
const [tasks, setTasks] = useState<TaskResponse[]>([])
|
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
|
||||||
const [projects, setProjects] = useState<Project[]>([])
|
|
||||||
const [categories, setCategories] = useState<Category[]>([])
|
|
||||||
const [assignees, setAssignees] = useState<TaskAssignee[]>([])
|
|
||||||
const [filters, setFilters] = useState<TaskFilters>(DEFAULT_TASK_FILTERS)
|
|
||||||
const [currentUserAssigneeId, setCurrentUserAssigneeId] = useState<number | null>(null)
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { activeOrg, user } = useAuth()
|
const { user } = useAuth()
|
||||||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
const {
|
||||||
|
tasks,
|
||||||
const loadTasks = async (currentFilters: TaskFilters, silent = false) => {
|
isLoading,
|
||||||
if (!activeOrg) return
|
projects,
|
||||||
if (!silent) setIsLoading(true)
|
categories,
|
||||||
try {
|
assignees,
|
||||||
const response = await taskService.getTasks({
|
filters,
|
||||||
organizationId: activeOrg.id,
|
currentUserAssigneeId,
|
||||||
text: currentFilters.searchQuery || undefined,
|
loadTasks,
|
||||||
projectIds: currentFilters.projectIds.length > 0 ? currentFilters.projectIds : undefined,
|
handleFiltersChange,
|
||||||
statuses: currentFilters.statuses.length > 0 ? currentFilters.statuses : undefined,
|
} = useTaskPage()
|
||||||
categoryIds: currentFilters.categoryIds.length > 0 ? currentFilters.categoryIds : undefined,
|
|
||||||
userIds: currentFilters.userIds.length > 0 ? currentFilters.userIds : undefined,
|
|
||||||
})
|
|
||||||
setTasks(response)
|
|
||||||
setProjects((current) => mergeProjects(current, response))
|
|
||||||
setAssignees((current) => {
|
|
||||||
const byId = new Map(current.map((assignee) => [assignee.id, assignee]))
|
|
||||||
extractAssignees(response).forEach((assignee) => byId.set(assignee.id, assignee))
|
|
||||||
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Erro ao carregar tarefas', error)
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!activeOrg) return
|
|
||||||
|
|
||||||
const init = async () => {
|
|
||||||
setFilters(DEFAULT_TASK_FILTERS)
|
|
||||||
setProjects([])
|
|
||||||
setAssignees([])
|
|
||||||
setCategories([])
|
|
||||||
|
|
||||||
const [members] = await Promise.all([
|
|
||||||
organizationService.listMembers(activeOrg.id),
|
|
||||||
categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {}),
|
|
||||||
])
|
|
||||||
|
|
||||||
const assigneesData = members.map((m) => ({
|
|
||||||
id: m.userId,
|
|
||||||
name: m.userName,
|
|
||||||
email: m.userEmail,
|
|
||||||
photo: m.userPhoto ?? null,
|
|
||||||
}))
|
|
||||||
setAssignees(assigneesData)
|
|
||||||
|
|
||||||
const currentMember = members.find((m) => m.userEmail === user?.email)
|
|
||||||
const userId = currentMember?.userId ?? null
|
|
||||||
setCurrentUserAssigneeId(userId)
|
|
||||||
|
|
||||||
const initialFilters = userId
|
|
||||||
? { ...DEFAULT_TASK_FILTERS, userIds: [userId] }
|
|
||||||
: DEFAULT_TASK_FILTERS
|
|
||||||
setFilters(initialFilters)
|
|
||||||
void loadTasks(initialFilters)
|
|
||||||
}
|
|
||||||
|
|
||||||
void init()
|
|
||||||
}, [activeOrg])
|
|
||||||
|
|
||||||
const handleFiltersChange = (newFilters: TaskFilters) => {
|
|
||||||
setFilters(newFilters)
|
|
||||||
if (debounceRef.current) clearTimeout(debounceRef.current)
|
|
||||||
debounceRef.current = setTimeout(() => {
|
|
||||||
void loadTasks(newFilters)
|
|
||||||
}, 300)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onDragEnd = async (result: DropResult) => {
|
const onDragEnd = async (result: DropResult) => {
|
||||||
const { destination, source, draggableId } = result
|
const { destination, source, draggableId } = result
|
||||||
|
|
@ -153,13 +58,9 @@ export function TaskBoardPage() {
|
||||||
const taskId = Number.parseInt(draggableId)
|
const taskId = Number.parseInt(draggableId)
|
||||||
const newStatus = destination.droppableId as TaskStatus
|
const newStatus = destination.droppableId as TaskStatus
|
||||||
|
|
||||||
const updatedTasks = tasks.map((t) =>
|
|
||||||
t.id === taskId ? { ...t, status: newStatus } : t,
|
|
||||||
)
|
|
||||||
setTasks(updatedTasks)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await taskService.updateTaskStatus(taskId, newStatus)
|
await taskService.updateTaskStatus(taskId, newStatus)
|
||||||
|
await loadTasks(filters, true)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao atualizar status da tarefa', error)
|
console.error('Erro ao atualizar status da tarefa', error)
|
||||||
void loadTasks(filters, true)
|
void loadTasks(filters, true)
|
||||||
|
|
|
||||||
|
|
@ -11,23 +11,17 @@ import {
|
||||||
Tag,
|
Tag,
|
||||||
XCircle,
|
XCircle,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import { taskService } from '../services/taskService'
|
import type { TaskResponse } from '../types/task'
|
||||||
import type { Project } from '../services/projectService'
|
|
||||||
import { projectService } from '../services/projectService'
|
|
||||||
import { categoryService } from '../services/categoryService'
|
|
||||||
import { organizationService } from '../services/organizationService'
|
|
||||||
import type { Category } from '../types/category'
|
|
||||||
import { cn } from '../lib/utils'
|
import { cn } from '../lib/utils'
|
||||||
import type { TaskAssignee, TaskResponse } from '../types/task'
|
|
||||||
import { TaskTimer } from '../components/TaskTimer'
|
import { TaskTimer } from '../components/TaskTimer'
|
||||||
import { TaskFilterBar } from '../components/TaskFilterBar'
|
import { TaskFilterBar } from '../components/TaskFilterBar'
|
||||||
import { DEFAULT_TASK_FILTERS, type TaskFilters } from '../components/taskFilters'
|
import { DEFAULT_TASK_FILTERS } from '../components/taskFilters'
|
||||||
import { CategoryBadge } from '../components/CategoryBadge'
|
import { CategoryBadge } from '../components/CategoryBadge'
|
||||||
import { UserAvatar } from '../components/UserAvatar'
|
import { UserAvatar } from '../components/UserAvatar'
|
||||||
import { useAuth } from '../contexts/AuthContext'
|
import { useAuth } from '../contexts/AuthContext'
|
||||||
|
import { useTaskPage } from '../hooks/useTaskPage'
|
||||||
|
|
||||||
function getStatusConfig(status: TaskResponse['status']) {
|
function getStatusConfig(status: TaskResponse['status']) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
|
@ -58,115 +52,20 @@ function getStatusConfig(status: TaskResponse['status']) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeProjects(existing: Project[], tasks: TaskResponse[]) {
|
|
||||||
const byId = new Map(existing.map((project) => [project.id, project]))
|
|
||||||
|
|
||||||
tasks.forEach((task) => {
|
|
||||||
if (task.project) {
|
|
||||||
byId.set(task.project.id, {
|
|
||||||
id: task.project.id,
|
|
||||||
name: task.project.name,
|
|
||||||
color: task.project.color,
|
|
||||||
icon: task.project.icon,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractAssignees(tasks: TaskResponse[]) {
|
|
||||||
const byId = new Map<number, TaskAssignee>()
|
|
||||||
|
|
||||||
tasks.forEach((task) => {
|
|
||||||
if (task.user) {
|
|
||||||
byId.set(task.user.id, task.user)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TaskListPage() {
|
export function TaskListPage() {
|
||||||
const [tasks, setTasks] = useState<TaskResponse[]>([])
|
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
|
||||||
const [projects, setProjects] = useState<Project[]>([])
|
|
||||||
const [categories, setCategories] = useState<Category[]>([])
|
|
||||||
const [assignees, setAssignees] = useState<TaskAssignee[]>([])
|
|
||||||
const [filters, setFilters] = useState<TaskFilters>(DEFAULT_TASK_FILTERS)
|
|
||||||
const [currentUserAssigneeId, setCurrentUserAssigneeId] = useState<number | null>(null)
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { activeOrg, user } = useAuth()
|
const { user } = useAuth()
|
||||||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
const {
|
||||||
|
tasks,
|
||||||
const loadTasks = async (currentFilters: TaskFilters, silent = false) => {
|
isLoading,
|
||||||
if (!activeOrg) return
|
projects,
|
||||||
if (!silent) setIsLoading(true)
|
categories,
|
||||||
try {
|
assignees,
|
||||||
const response = await taskService.getTasks({
|
filters,
|
||||||
organizationId: activeOrg.id,
|
currentUserAssigneeId,
|
||||||
text: currentFilters.searchQuery || undefined,
|
loadTasks,
|
||||||
projectIds: currentFilters.projectIds.length > 0 ? currentFilters.projectIds : undefined,
|
handleFiltersChange,
|
||||||
statuses: currentFilters.statuses.length > 0 ? currentFilters.statuses : undefined,
|
} = useTaskPage({ fetchProjects: true })
|
||||||
categoryIds: currentFilters.categoryIds.length > 0 ? currentFilters.categoryIds : undefined,
|
|
||||||
userIds: currentFilters.userIds.length > 0 ? currentFilters.userIds : undefined,
|
|
||||||
})
|
|
||||||
setTasks(response)
|
|
||||||
setProjects((current) => mergeProjects(current, response))
|
|
||||||
setAssignees((current) => {
|
|
||||||
const byId = new Map(current.map((assignee) => [assignee.id, assignee]))
|
|
||||||
extractAssignees(response).forEach((assignee) => byId.set(assignee.id, assignee))
|
|
||||||
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name))
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Erro ao carregar tarefas', error)
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!activeOrg) return
|
|
||||||
|
|
||||||
const init = async () => {
|
|
||||||
setFilters(DEFAULT_TASK_FILTERS)
|
|
||||||
setCategories([])
|
|
||||||
|
|
||||||
const [members] = await Promise.all([
|
|
||||||
organizationService.listMembers(activeOrg.id),
|
|
||||||
categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {}),
|
|
||||||
projectService.listByOrganization(activeOrg.id).then(setProjects).catch(() => {}),
|
|
||||||
])
|
|
||||||
|
|
||||||
const assigneesData = members.map((m) => ({
|
|
||||||
id: m.userId,
|
|
||||||
name: m.userName,
|
|
||||||
email: m.userEmail,
|
|
||||||
photo: m.userPhoto ?? null,
|
|
||||||
}))
|
|
||||||
setAssignees(assigneesData)
|
|
||||||
|
|
||||||
const currentMember = members.find((m) => m.userEmail === user?.email)
|
|
||||||
const userId = currentMember?.userId ?? null
|
|
||||||
setCurrentUserAssigneeId(userId)
|
|
||||||
|
|
||||||
const initialFilters = userId
|
|
||||||
? { ...DEFAULT_TASK_FILTERS, userIds: [userId] }
|
|
||||||
: DEFAULT_TASK_FILTERS
|
|
||||||
setFilters(initialFilters)
|
|
||||||
void loadTasks(initialFilters)
|
|
||||||
}
|
|
||||||
|
|
||||||
void init()
|
|
||||||
}, [activeOrg])
|
|
||||||
|
|
||||||
const handleFiltersChange = (newFilters: TaskFilters) => {
|
|
||||||
setFilters(newFilters)
|
|
||||||
if (debounceRef.current) clearTimeout(debounceRef.current)
|
|
||||||
debounceRef.current = setTimeout(() => {
|
|
||||||
void loadTasks(newFilters)
|
|
||||||
}, 300)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8 pb-12">
|
<div className="space-y-8 pb-12">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue