feat: add "Mostrar apenas as minhas" checkbox to task filters
Adds a pre-checked checkbox next to the employee filter that automatically filters tasks to the logged-in user on page load. Unchecking restores the free-select dropdown behavior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f01d72c2bb
commit
119d896a59
3 changed files with 79 additions and 16 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"
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ 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 { Project } from '../services/projectService'
|
||||||
import { categoryService } from '../services/categoryService'
|
import { categoryService } from '../services/categoryService'
|
||||||
|
import { organizationService } from '../services/organizationService'
|
||||||
import type { Category } from '../types/category'
|
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 type { TaskAssignee, TaskResponse, TaskStatus } from '../types/task'
|
||||||
|
|
@ -63,6 +64,7 @@ export function TaskBoardPage() {
|
||||||
const [categories, setCategories] = useState<Category[]>([])
|
const [categories, setCategories] = useState<Category[]>([])
|
||||||
const [assignees, setAssignees] = useState<TaskAssignee[]>([])
|
const [assignees, setAssignees] = useState<TaskAssignee[]>([])
|
||||||
const [filters, setFilters] = useState<TaskFilters>(DEFAULT_TASK_FILTERS)
|
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 { activeOrg, user } = useAuth()
|
||||||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
|
@ -95,12 +97,38 @@ export function TaskBoardPage() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeOrg) return
|
if (!activeOrg) return
|
||||||
setFilters(DEFAULT_TASK_FILTERS)
|
|
||||||
setProjects([])
|
const init = async () => {
|
||||||
setAssignees([])
|
setFilters(DEFAULT_TASK_FILTERS)
|
||||||
setCategories([])
|
setProjects([])
|
||||||
void loadTasks(DEFAULT_TASK_FILTERS)
|
setAssignees([])
|
||||||
categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {})
|
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])
|
}, [activeOrg])
|
||||||
|
|
||||||
const handleFiltersChange = (newFilters: TaskFilters) => {
|
const handleFiltersChange = (newFilters: TaskFilters) => {
|
||||||
|
|
@ -182,6 +210,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)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ export function TaskListPage() {
|
||||||
const [categories, setCategories] = useState<Category[]>([])
|
const [categories, setCategories] = useState<Category[]>([])
|
||||||
const [assignees, setAssignees] = useState<TaskAssignee[]>([])
|
const [assignees, setAssignees] = useState<TaskAssignee[]>([])
|
||||||
const [filters, setFilters] = useState<TaskFilters>(DEFAULT_TASK_FILTERS)
|
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 { activeOrg, user } = useAuth()
|
||||||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
|
@ -126,22 +127,37 @@ export function TaskListPage() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeOrg) return
|
if (!activeOrg) return
|
||||||
setFilters(DEFAULT_TASK_FILTERS)
|
|
||||||
setCategories([])
|
|
||||||
void loadTasks(DEFAULT_TASK_FILTERS)
|
|
||||||
|
|
||||||
categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {})
|
const init = async () => {
|
||||||
|
setFilters(DEFAULT_TASK_FILTERS)
|
||||||
|
setCategories([])
|
||||||
|
|
||||||
projectService.listByOrganization(activeOrg.id).then(setProjects).catch(() => {})
|
const [members] = await Promise.all([
|
||||||
|
organizationService.listMembers(activeOrg.id),
|
||||||
|
categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {}),
|
||||||
|
projectService.listByOrganization(activeOrg.id).then(setProjects).catch(() => {}),
|
||||||
|
])
|
||||||
|
|
||||||
organizationService.listMembers(activeOrg.id).then((members) => {
|
const assigneesData = members.map((m) => ({
|
||||||
setAssignees(members.map((m) => ({
|
|
||||||
id: m.userId,
|
id: m.userId,
|
||||||
name: m.userName,
|
name: m.userName,
|
||||||
email: m.userEmail,
|
email: m.userEmail,
|
||||||
photo: m.userPhoto ?? null,
|
photo: m.userPhoto ?? null,
|
||||||
})))
|
}))
|
||||||
}).catch(() => {})
|
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])
|
}, [activeOrg])
|
||||||
|
|
||||||
const handleFiltersChange = (newFilters: TaskFilters) => {
|
const handleFiltersChange = (newFilters: TaskFilters) => {
|
||||||
|
|
@ -193,6 +209,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