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:
parent
cc68c85246
commit
5b1d73ea43
3 changed files with 78 additions and 49 deletions
12
docs/alteracoes-2025-11-13.md
Normal file
12
docs/alteracoes-2025-11-13.md
Normal 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.
|
||||||
|
|
||||||
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue