feat: add queue summary widget and layout fixes
This commit is contained in:
parent
f7976e2c39
commit
a542846313
12 changed files with 350 additions and 45 deletions
|
|
@ -174,9 +174,10 @@ export function TicketCustomFieldsList({ record, emptyMessage, className }: Tick
|
|||
|
||||
type TicketCustomFieldsSectionProps = {
|
||||
ticket: TicketWithDetails
|
||||
hidePreview?: boolean
|
||||
}
|
||||
|
||||
export function TicketCustomFieldsSection({ ticket }: TicketCustomFieldsSectionProps) {
|
||||
export function TicketCustomFieldsSection({ ticket, hidePreview = false }: TicketCustomFieldsSectionProps) {
|
||||
const { convexUserId, role } = useAuth()
|
||||
const canEdit = Boolean(convexUserId && (role === "admin" || role === "agent"))
|
||||
|
||||
|
|
@ -318,10 +319,14 @@ export function TicketCustomFieldsSection({ ticket }: TicketCustomFieldsSectionP
|
|||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
<TicketCustomFieldsList
|
||||
record={ticket.customFields}
|
||||
emptyMessage="Nenhum campo adicional preenchido neste chamado."
|
||||
/>
|
||||
{hidePreview ? (
|
||||
<p className="text-xs text-neutral-500">Visualize os valores no resumo principal.</p>
|
||||
) : (
|
||||
<TicketCustomFieldsList
|
||||
record={ticket.customFields}
|
||||
emptyMessage="Nenhum campo adicional preenchido neste chamado."
|
||||
/>
|
||||
)}
|
||||
|
||||
<Dialog open={editorOpen} onOpenChange={setEditorOpen}>
|
||||
<DialogContent className="max-w-3xl gap-4">
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<TicketCustomFieldsSection ticket={ticket} />
|
||||
<TicketCustomFieldsSection ticket={ticket} hidePreview />
|
||||
|
||||
<section className="space-y-3">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
|
|
|
|||
|
|
@ -16,13 +16,14 @@ interface TicketQueueSummaryProps {
|
|||
export function TicketQueueSummaryCards({ queues }: TicketQueueSummaryProps) {
|
||||
const { convexUserId, isStaff } = useAuth()
|
||||
const enabled = Boolean(isStaff && convexUserId)
|
||||
const shouldFetch = Boolean(!queues && enabled)
|
||||
const fromServer = useQuery(
|
||||
api.queues.summary,
|
||||
enabled ? { tenantId: DEFAULT_TENANT_ID, viewerId: convexUserId as Id<"users"> } : "skip"
|
||||
shouldFetch ? { tenantId: DEFAULT_TENANT_ID, viewerId: convexUserId as Id<"users"> } : "skip"
|
||||
) as TicketQueueSummary[] | undefined
|
||||
const data: TicketQueueSummary[] = queues ?? fromServer ?? []
|
||||
|
||||
if (!queues && fromServer === undefined) {
|
||||
if (!queues && shouldFetch && fromServer === undefined) {
|
||||
return (
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { Textarea } from "@/components/ui/textarea"
|
|||
import { Spinner } from "@/components/ui/spinner"
|
||||
import { useTicketCategories } from "@/hooks/use-ticket-categories"
|
||||
import { useDefaultQueues } from "@/hooks/use-default-queues"
|
||||
import { mapTicketCustomFields } from "@/lib/ticket-custom-fields"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
|
|
@ -213,6 +214,7 @@ export function TicketSummaryHeader({ ticket }: TicketHeaderProps) {
|
|||
queuesEnabled ? { tenantId: ticket.tenantId, viewerId: convexUserId as Id<"users"> } : "skip"
|
||||
)
|
||||
const queues: TicketQueueSummary[] = Array.isArray(queuesResult) ? queuesResult : []
|
||||
const customFieldEntries = useMemo(() => mapTicketCustomFields(ticket.customFields), [ticket.customFields])
|
||||
const { categories, isLoading: categoriesLoading } = useTicketCategories(ticket.tenantId)
|
||||
const workSummaryRemote = useQuery(
|
||||
api.tickets.workSummary,
|
||||
|
|
@ -1583,6 +1585,24 @@ export function TicketSummaryHeader({ ticket }: TicketHeaderProps) {
|
|||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mt-6 space-y-2">
|
||||
<span className={sectionLabelClass}>Informações adicionais</span>
|
||||
{customFieldEntries.length > 0 ? (
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
{customFieldEntries.map((entry) => (
|
||||
<div
|
||||
key={entry.key}
|
||||
className="rounded-2xl border border-slate-200 bg-white px-4 py-3 shadow-sm"
|
||||
>
|
||||
<p className="text-xs font-semibold uppercase tracking-wide text-neutral-500">{entry.label}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-neutral-900">{entry.formattedValue}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-xs text-neutral-500">Nenhum campo adicional preenchido para este chamado.</p>
|
||||
)}
|
||||
</div>
|
||||
<Dialog open={pauseDialogOpen} onOpenChange={setPauseDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue