feat: add "Mostrar apenas as minhas" checkbox to task filters
feat: add "Mostrar apenas as minhas" checkbox to task filters
This commit is contained in:
commit
8fe40e800a
4 changed files with 202 additions and 187 deletions
|
|
@ -22,6 +22,7 @@ interface TaskFilterBarProps {
|
||||||
projects: Project[]
|
projects: Project[]
|
||||||
categories: Category[]
|
categories: Category[]
|
||||||
assignees: TaskAssignee[]
|
assignees: TaskAssignee[]
|
||||||
|
currentUserId?: number
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
onRefresh?: () => void
|
onRefresh?: () => void
|
||||||
}
|
}
|
||||||
|
|
@ -32,6 +33,7 @@ export function TaskFilterBar({
|
||||||
projects,
|
projects,
|
||||||
categories,
|
categories,
|
||||||
assignees,
|
assignees,
|
||||||
|
currentUserId,
|
||||||
isLoading,
|
isLoading,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
}: TaskFilterBarProps) {
|
}: TaskFilterBarProps) {
|
||||||
|
|
@ -98,7 +100,22 @@ export function TaskFilterBar({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{assignees.length > 0 && (
|
{assignees.length > 0 && (
|
||||||
<div className="grid gap-3">
|
<div className="grid gap-2">
|
||||||
|
{currentUserId !== undefined && (
|
||||||
|
<label className="flex cursor-pointer items-center gap-2 self-start">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={filters.userIds.length === 1 && filters.userIds[0] === currentUserId}
|
||||||
|
onChange={(e) =>
|
||||||
|
update({ userIds: e.target.checked ? [currentUserId] : [] })
|
||||||
|
}
|
||||||
|
className="h-4 w-4 accent-brand"
|
||||||
|
/>
|
||||||
|
<span className="text-xs font-semibold text-text-muted">
|
||||||
|
Mostrar apenas as minhas
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
<MultiSelectDropdown
|
<MultiSelectDropdown
|
||||||
label="Funcionario"
|
label="Funcionario"
|
||||||
allLabel="Todos os funcionarios"
|
allLabel="Todos os funcionarios"
|
||||||
|
|
|
||||||
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,20 +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 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' },
|
||||||
|
|
@ -32,84 +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 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
|
|
||||||
setFilters(DEFAULT_TASK_FILTERS)
|
|
||||||
setProjects([])
|
|
||||||
setAssignees([])
|
|
||||||
setCategories([])
|
|
||||||
void loadTasks(DEFAULT_TASK_FILTERS)
|
|
||||||
categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {})
|
|
||||||
}, [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
|
||||||
|
|
@ -125,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)
|
||||||
|
|
@ -182,6 +111,7 @@ export function TaskBoardPage() {
|
||||||
projects={projects}
|
projects={projects}
|
||||||
categories={categories}
|
categories={categories}
|
||||||
assignees={assignees}
|
assignees={assignees}
|
||||||
|
currentUserId={currentUserAssigneeId ?? undefined}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onRefresh={() => void loadTasks(filters)}
|
onRefresh={() => void loadTasks(filters)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -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,99 +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 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
|
|
||||||
setFilters(DEFAULT_TASK_FILTERS)
|
|
||||||
setCategories([])
|
|
||||||
void loadTasks(DEFAULT_TASK_FILTERS)
|
|
||||||
|
|
||||||
categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {})
|
|
||||||
|
|
||||||
projectService.listByOrganization(activeOrg.id).then(setProjects).catch(() => {})
|
|
||||||
|
|
||||||
organizationService.listMembers(activeOrg.id).then((members) => {
|
|
||||||
setAssignees(members.map((m) => ({
|
|
||||||
id: m.userId,
|
|
||||||
name: m.userName,
|
|
||||||
email: m.userEmail,
|
|
||||||
photo: m.userPhoto ?? null,
|
|
||||||
})))
|
|
||||||
}).catch(() => {})
|
|
||||||
}, [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">
|
||||||
|
|
@ -193,6 +108,7 @@ export function TaskListPage() {
|
||||||
projects={projects}
|
projects={projects}
|
||||||
categories={categories}
|
categories={categories}
|
||||||
assignees={assignees}
|
assignees={assignees}
|
||||||
|
currentUserId={currentUserAssigneeId ?? undefined}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onRefresh={() => void loadTasks(filters)}
|
onRefresh={() => void loadTasks(filters)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue