feat(export,tickets,forms,emails):\n- Corrige scroll de Dialogs e melhora UI de seleção de colunas (ícones e separador)\n- Ajusta rota/params da exportação em massa e adiciona modal de exportação individual\n- Renomeia 'Chamado padrão' para 'Chamado' e garante visibilidade total para admin/agente\n- Adiciona toggles por empresa/usuário para habilitar Admissão/Desligamento\n- Exibe badge do tipo de solicitação na listagem e no cabeçalho do ticket\n- Prepara notificações por e-mail (comentário público e encerramento) via SMTP\n
This commit is contained in:
parent
a8333c010f
commit
06deb99bcd
12 changed files with 543 additions and 17 deletions
|
|
@ -80,7 +80,9 @@ import { Textarea } from "@/components/ui/textarea"
|
|||
import { TimePicker } from "@/components/ui/time-picker"
|
||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
|
||||
import { useQuery } from "convex/react"
|
||||
import { useQuery, useMutation } from "convex/react"
|
||||
import { useAuth } from "@/lib/auth-client"
|
||||
import type { Id } from "@/convex/_generated/dataModel"
|
||||
import { api } from "@/convex/_generated/api"
|
||||
import { MultiValueInput } from "@/components/ui/multi-value-input"
|
||||
import { AdminDevicesOverview } from "@/components/admin/devices/admin-devices-overview"
|
||||
|
|
@ -1685,6 +1687,13 @@ function CompanySheet({ tenantId, editor, onClose, onCreated, onUpdated }: Compa
|
|||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem value="requestTypes" className="rounded-lg border border-border/60 bg-muted/20 px-4">
|
||||
<AccordionTrigger className="py-3 font-semibold">Tipos de solicitação</AccordionTrigger>
|
||||
<AccordionContent className="pb-5">
|
||||
<CompanyRequestTypesControls tenantId={tenantId} companyId={editor?.mode === "edit" ? editor.company.id : null} />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
{editor?.mode === "edit" ? (
|
||||
<AccordionItem value="machines" className="rounded-lg border border-border/60 bg-muted/20 px-4">
|
||||
<AccordionTrigger className="py-3 font-semibold">Dispositivos vinculadas</AccordionTrigger>
|
||||
|
|
@ -2173,3 +2182,69 @@ function BusinessHoursEditor({ form }: BusinessHoursEditorProps) {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
type CompanyRequestTypesControlsProps = { tenantId?: string | null; companyId: string | null }
|
||||
function CompanyRequestTypesControls({ tenantId, companyId }: CompanyRequestTypesControlsProps) {
|
||||
const { convexUserId } = useAuth()
|
||||
const canLoad = Boolean(tenantId && convexUserId)
|
||||
const settings = useQuery(
|
||||
api.ticketFormSettings.list,
|
||||
canLoad ? { tenantId: tenantId as string, viewerId: convexUserId as Id<"users"> } : "skip"
|
||||
) as Array<{ template: string; scope: string; companyId?: string | null; enabled: boolean; updatedAt: number }> | undefined
|
||||
const upsert = useMutation(api.ticketFormSettings.upsert)
|
||||
|
||||
const resolveEnabled = (template: "admissao" | "desligamento") => {
|
||||
const scoped = (settings ?? []).filter((s) => s.template === template)
|
||||
const base = true
|
||||
if (!companyId) return base
|
||||
const latest = scoped
|
||||
.filter((s) => s.scope === "company" && String(s.companyId ?? "") === String(companyId))
|
||||
.sort((a, b) => b.updatedAt - a.updatedAt)[0]
|
||||
return typeof latest?.enabled === "boolean" ? latest.enabled : base
|
||||
}
|
||||
|
||||
const admissaoEnabled = resolveEnabled("admissao")
|
||||
const desligamentoEnabled = resolveEnabled("desligamento")
|
||||
|
||||
const handleToggle = async (template: "admissao" | "desligamento", enabled: boolean) => {
|
||||
if (!tenantId || !convexUserId || !companyId) return
|
||||
try {
|
||||
await upsert({
|
||||
tenantId,
|
||||
actorId: convexUserId as Id<"users">,
|
||||
template,
|
||||
scope: "company",
|
||||
companyId: companyId as unknown as Id<"companies">,
|
||||
enabled,
|
||||
})
|
||||
toast.success("Configuração salva.")
|
||||
} catch (error) {
|
||||
console.error("Falha ao salvar configuração de formulário", error)
|
||||
toast.error("Não foi possível salvar a configuração.")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm text-muted-foreground">Defina quais tipos de solicitação estão disponíveis para colaboradores/gestores desta empresa. Administradores e agentes sempre veem todas as opções.</p>
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
<label className="flex items-center gap-2 text-sm text-foreground">
|
||||
<Checkbox
|
||||
checked={admissaoEnabled}
|
||||
onCheckedChange={(v) => handleToggle("admissao", Boolean(v))}
|
||||
disabled={!companyId}
|
||||
/>
|
||||
<span>Admissão de colaborador</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 text-sm text-foreground">
|
||||
<Checkbox
|
||||
checked={desligamentoEnabled}
|
||||
onCheckedChange={(v) => handleToggle("desligamento", Boolean(v))}
|
||||
disabled={!companyId}
|
||||
/>
|
||||
<span>Desligamento de colaborador</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue