desktop(portal): ocultar filtros avançados (fila/empresa/responsável) para colaboradores e gestores quando aberto via app desktop; manter categoria/status/ordenação/período; docs atualizados

This commit is contained in:
Esdras Renan 2025-11-13 13:04:17 -03:00
parent cc68c85246
commit 5b1d73ea43
3 changed files with 78 additions and 49 deletions

View file

@ -0,0 +1,12 @@
Alterações em 13/11/2025 — Portal no app desktop
- Ocultamos filtros avançados em Portal ▸ Meus chamados quando o acesso vem do app desktop (WebView com sessão de máquina) e o usuário final é `collaborator` ou `manager`.
- Filtros ocultos: Fila, Empresa, Responsável.
- Filtros mantidos: Categoria, Status, Ordenação e Período.
- Implementação:
- `src/components/portal/portal-ticket-filters.tsx`: adicionada prop opcional `hideAdvancedFilters` para suprimir os três filtros mencionados sem quebrar o layout.
- `src/components/portal/portal-ticket-list.tsx`: definimos `hideAdvancedFilters` como `true` quando `machineContext` está presente e a `role` efetiva é `collaborator` ou `manager`.
- Observações:
- A detecção do app desktop usa o `machineContext` carregado via `/api/machines/session` (não foi necessário cookie adicional).
- A mudança afeta somente o portal aberto pelo desktop; no navegador os filtros permanecem inalterados.

View file

@ -40,6 +40,12 @@ type PortalTicketFiltersProps = {
companies: string[] companies: string[]
categories: Option[] categories: Option[]
assignees: Option[] assignees: Option[]
/**
* Quando verdadeiro, oculta filtros avançados que não devem aparecer para
* usuários finais no app desktop (fila, empresa e responsável).
* Mantemos categoria, status, ordenação e período.
*/
hideAdvancedFilters?: boolean
} }
export function PortalTicketFilters({ export function PortalTicketFilters({
@ -50,6 +56,7 @@ export function PortalTicketFilters({
companies, companies,
categories, categories,
assignees, assignees,
hideAdvancedFilters = false,
}: PortalTicketFiltersProps) { }: PortalTicketFiltersProps) {
const handleChange = (partial: Partial<PortalTicketFiltersState>) => { const handleChange = (partial: Partial<PortalTicketFiltersState>) => {
onFiltersChange(partial) onFiltersChange(partial)
@ -58,6 +65,7 @@ export function PortalTicketFilters({
return ( return (
<div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm"> <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm">
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3"> <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
{!hideAdvancedFilters && (
<Select <Select
value={filters.queue ?? ALL_VALUE} value={filters.queue ?? ALL_VALUE}
onValueChange={(value) => handleChange({ queue: value === ALL_VALUE ? null : value })} onValueChange={(value) => handleChange({ queue: value === ALL_VALUE ? null : value })}
@ -74,6 +82,8 @@ export function PortalTicketFilters({
))} ))}
</SelectContent> </SelectContent>
</Select> </Select>
)}
{!hideAdvancedFilters && (
<Select <Select
value={filters.company ?? ALL_VALUE} value={filters.company ?? ALL_VALUE}
onValueChange={(value) => handleChange({ company: value === ALL_VALUE ? null : value })} onValueChange={(value) => handleChange({ company: value === ALL_VALUE ? null : value })}
@ -90,6 +100,7 @@ export function PortalTicketFilters({
))} ))}
</SelectContent> </SelectContent>
</Select> </Select>
)}
<Select <Select
value={filters.categoryId ?? ALL_VALUE} value={filters.categoryId ?? ALL_VALUE}
onValueChange={(value) => handleChange({ categoryId: value === ALL_VALUE ? null : value })} onValueChange={(value) => handleChange({ categoryId: value === ALL_VALUE ? null : value })}
@ -106,6 +117,7 @@ export function PortalTicketFilters({
))} ))}
</SelectContent> </SelectContent>
</Select> </Select>
{!hideAdvancedFilters && (
<Select <Select
value={filters.assigneeId ?? ALL_VALUE} value={filters.assigneeId ?? ALL_VALUE}
onValueChange={(value) => handleChange({ assigneeId: value === ALL_VALUE ? null : value })} onValueChange={(value) => handleChange({ assigneeId: value === ALL_VALUE ? null : value })}
@ -122,6 +134,7 @@ export function PortalTicketFilters({
))} ))}
</SelectContent> </SelectContent>
</Select> </Select>
)}
<Select value={filters.status} onValueChange={(value) => handleChange({ status: value as PortalTicketFiltersState["status"] })}> <Select value={filters.status} onValueChange={(value) => handleChange({ status: value as PortalTicketFiltersState["status"] })}>
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
<SelectValue placeholder="Status" /> <SelectValue placeholder="Status" />

View file

@ -21,7 +21,7 @@ import {
} from "@/components/portal/portal-ticket-filters" } from "@/components/portal/portal-ticket-filters"
export function PortalTicketList() { export function PortalTicketList() {
const { convexUserId, session, machineContext } = useAuth() const { convexUserId, session, machineContext, role } = useAuth()
const viewerId = (convexUserId ?? machineContext?.assignedUserId ?? null) as Id<"users"> | null const viewerId = (convexUserId ?? machineContext?.assignedUserId ?? null) as Id<"users"> | null
@ -43,6 +43,9 @@ export function PortalTicketList() {
const [filters, setFilters] = useState<PortalTicketFiltersState>(defaultPortalTicketFilters) const [filters, setFilters] = useState<PortalTicketFiltersState>(defaultPortalTicketFilters)
// No app desktop, colaboradores e gestores não devem ver filtros avançados
const hideAdvancedFilters = Boolean(machineContext) && (role === "collaborator" || role === "manager")
const queueOptions = useMemo(() => { const queueOptions = useMemo(() => {
const set = new Set<string>() const set = new Set<string>()
;(tickets as Ticket[]).forEach((ticket) => { ;(tickets as Ticket[]).forEach((ticket) => {
@ -214,6 +217,7 @@ export function PortalTicketList() {
companies={companyOptions} companies={companyOptions}
categories={categoryOptions} categories={categoryOptions}
assignees={assigneeOptions} assignees={assigneeOptions}
hideAdvancedFilters={hideAdvancedFilters}
/> />
{filteredTickets.length === 0 ? ( {filteredTickets.length === 0 ? (
<Card className="rounded-2xl border border-slate-200 bg-white py-8 text-center shadow-sm"> <Card className="rounded-2xl border border-slate-200 bg-white py-8 text-center shadow-sm">