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:
Gabriel Santana de Menezes 2026-05-20 15:51:40 -04:00
parent f01d72c2bb
commit 119d896a59
3 changed files with 79 additions and 16 deletions

View file

@ -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"

View file

@ -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)}
/> />

View file

@ -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)}
/> />