From 6a04ef4843eb1dadc761375e256f651f7505b560 Mon Sep 17 00:00:00 2001 From: Esdras Renan Date: Mon, 13 Oct 2025 17:47:39 -0300 Subject: [PATCH] Ajusta portal do cliente e desbloqueia abertura de chamados --- src/components/portal/portal-shell.tsx | 4 ++-- src/components/portal/portal-ticket-form.tsx | 21 +++++++++++++++----- src/components/tickets/category-select.tsx | 16 ++++++++++++++- src/components/tickets/new-ticket-dialog.tsx | 2 +- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/components/portal/portal-shell.tsx b/src/components/portal/portal-shell.tsx index 98dcabb..2b937e1 100644 --- a/src/components/portal/portal-shell.tsx +++ b/src/components/portal/portal-shell.tsx @@ -79,8 +79,8 @@ export function PortalShell({ children }: PortalShellProps) {
- - Portal do cliente + + Portal do Cliente Raven
diff --git a/src/components/portal/portal-ticket-form.tsx b/src/components/portal/portal-ticket-form.tsx index 697c4b0..a958cf7 100644 --- a/src/components/portal/portal-ticket-form.tsx +++ b/src/components/portal/portal-ticket-form.tsx @@ -1,6 +1,6 @@ "use client" -import { useMemo, useState } from "react" +import { useCallback, useMemo, useState } from "react" import { useRouter } from "next/navigation" import { useMutation } from "convex/react" import { toast } from "sonner" @@ -45,10 +45,20 @@ export function PortalTicketForm() { const [subcategoryId, setSubcategoryId] = useState(null) const [attachments, setAttachments] = useState>([]) const [isSubmitting, setIsSubmitting] = useState(false) + const [hasSubcategoryOptions, setHasSubcategoryOptions] = useState(false) const isFormValid = useMemo(() => { - return Boolean(subject.trim() && description.trim() && categoryId && subcategoryId) - }, [subject, description, categoryId, subcategoryId]) + return Boolean( + subject.trim() && + description.trim() && + categoryId && + (hasSubcategoryOptions ? subcategoryId : true) + ) + }, [subject, description, categoryId, subcategoryId, hasSubcategoryOptions]) + + const handleSecondaryOptionsChange = useCallback((hasOptions: boolean) => { + setHasSubcategoryOptions((prev) => (prev === hasOptions ? prev : hasOptions)) + }, []) async function handleSubmit(event: React.FormEvent) { event.preventDefault() @@ -76,7 +86,7 @@ export function PortalTicketForm() { queueId: undefined, requesterId: viewerId, categoryId: categoryId as Id<"ticketCategories">, - subcategoryId: subcategoryId as Id<"ticketSubcategories">, + subcategoryId: subcategoryId ? (subcategoryId as Id<"ticketSubcategories">) : undefined, }) if (plainDescription.length > 0) { @@ -159,9 +169,10 @@ export function PortalTicketForm() { subcategoryId={subcategoryId} onCategoryChange={setCategoryId} onSubcategoryChange={setSubcategoryId} + onSecondaryOptionsChange={handleSecondaryOptionsChange} layout="stacked" categoryLabel="Categoria *" - subcategoryLabel="Subcategoria *" + subcategoryLabel={hasSubcategoryOptions ? "Subcategoria *" : "Subcategoria (opcional)"} secondaryEmptyLabel="Selecione uma categoria" />
diff --git a/src/components/tickets/category-select.tsx b/src/components/tickets/category-select.tsx index 679e860..7701f0f 100644 --- a/src/components/tickets/category-select.tsx +++ b/src/components/tickets/category-select.tsx @@ -18,7 +18,8 @@ interface CategorySelectProps { categoryId: string | null subcategoryId: string | null onCategoryChange: (categoryId: string) => void - onSubcategoryChange: (subcategoryId: string) => void + onSubcategoryChange: (subcategoryId: string | null) => void + onSecondaryOptionsChange?: (hasSecondary: boolean) => void autoSelectFirst?: boolean disabled?: boolean categoryLabel?: string @@ -39,6 +40,7 @@ export function CategorySelectFields({ subcategoryId, onCategoryChange, onSubcategoryChange, + onSecondaryOptionsChange, autoSelectFirst = true, disabled = false, categoryLabel = "Primária", @@ -72,10 +74,22 @@ export function CategorySelectFields({ const first = secondaryOptions[0] if (first) { onSubcategoryChange(first.id) + } else { + onSubcategoryChange(null) } } }, [categoryId, secondaryOptions, subcategoryId, onSubcategoryChange]) + useEffect(() => { + onSecondaryOptionsChange?.(secondaryOptions.length > 0) + }, [secondaryOptions, onSecondaryOptionsChange]) + + useEffect(() => { + if (secondaryOptions.length === 0 && subcategoryId) { + onSubcategoryChange(null) + } + }, [secondaryOptions, subcategoryId, onSubcategoryChange]) + const containerClass = layout === "stacked" ? "flex flex-col gap-3" : "grid gap-3 sm:grid-cols-2" return ( diff --git a/src/components/tickets/new-ticket-dialog.tsx b/src/components/tickets/new-ticket-dialog.tsx index 2831853..45dd97e 100644 --- a/src/components/tickets/new-ticket-dialog.tsx +++ b/src/components/tickets/new-ticket-dialog.tsx @@ -112,7 +112,7 @@ export function NewTicketDialog() { } } - const handleSubcategoryChange = (value: string) => { + const handleSubcategoryChange = (value: string | null) => { const previous = form.getValues("subcategoryId") ?? "" const next = value ?? "" form.setValue("subcategoryId", next, {