sistema-de-chamados/src/app/agenda/agenda-page-client.tsx
2025-11-08 02:34:43 -03:00

121 lines
4.6 KiB
TypeScript

"use client"
import { useEffect, useMemo, useState } from "react"
import { useQuery } from "convex/react"
import { format } from "date-fns"
import { ptBR } from "date-fns/locale/pt-BR"
import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { mapTicketsFromServerList } from "@/lib/mappers/ticket"
import type { Ticket } from "@/lib/schemas/ticket"
import { AppShell } from "@/components/app-shell"
import { SiteHeader } from "@/components/site-header"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Button } from "@/components/ui/button"
import { CalendarPlus } from "lucide-react"
import { useAuth } from "@/lib/auth-client"
import { AgendaFilters, AgendaFilterState, AgendaPeriod, defaultAgendaFilters } from "@/components/agenda/agenda-filters"
import { AgendaSummaryView } from "@/components/agenda/agenda-summary-view"
import { AgendaCalendarView } from "@/components/agenda/agenda-calendar-view"
import { buildAgendaDataset, type AgendaDataset } from "@/lib/agenda-utils"
export function AgendaPageClient() {
const [activeTab, setActiveTab] = useState<"summary" | "calendar">("summary")
const [filters, setFilters] = useState<AgendaFilterState>(defaultAgendaFilters)
const { convexUserId, session } = useAuth()
const userId = convexUserId as Id<"users"> | null
const tenantId = session?.user?.tenantId ?? DEFAULT_TENANT_ID
const ticketsArgs = userId
? {
tenantId,
viewerId: userId,
status: undefined,
priority: filters.priorities.length ? filters.priorities : undefined,
queueId: undefined,
channel: undefined,
assigneeId: filters.onlyMyTickets ? userId : undefined,
search: undefined,
}
: "skip"
const ticketsRaw = useQuery(api.tickets.list, ticketsArgs)
const mappedTickets = useMemo<Ticket[] | null>(() => {
if (!Array.isArray(ticketsRaw)) return null
return mapTicketsFromServerList(ticketsRaw as unknown[])
}, [ticketsRaw])
const [cachedTickets, setCachedTickets] = useState<Ticket[]>([])
useEffect(() => {
if (mappedTickets) {
setCachedTickets(mappedTickets)
}
}, [mappedTickets])
const effectiveTickets = mappedTickets ?? cachedTickets
const isInitialLoading = !mappedTickets && cachedTickets.length === 0 && ticketsArgs !== "skip"
const dataset: AgendaDataset = useMemo(
() => buildAgendaDataset(effectiveTickets, filters),
[effectiveTickets, filters]
)
const greeting = getGreetingMessage()
const firstName = session?.user?.name?.split(" ")[0] ?? session?.user?.email?.split("@")[0] ?? "equipe"
const rangeDescription = formatRangeDescription(filters.period, dataset.range)
const headerLead = `${greeting}, ${firstName}! ${rangeDescription}`
return (
<AppShell
header={
<SiteHeader
title="Agenda"
lead={headerLead}
secondaryAction={
<Button variant="secondary" size="sm" className="gap-2" disabled>
<CalendarPlus className="size-4" />
Em breve: novo compromisso
</Button>
}
/>
}
>
<div className="flex flex-col gap-6 px-4 lg:px-6">
<AgendaFilters filters={filters} onChange={setFilters} queues={dataset.availableQueues} />
<Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as typeof activeTab)}>
<TabsList className="mb-4">
<TabsTrigger value="summary">Resumo</TabsTrigger>
<TabsTrigger value="calendar">Calendário</TabsTrigger>
</TabsList>
<TabsContent value="summary" className="focus-visible:outline-none">
<AgendaSummaryView data={dataset} isLoading={isInitialLoading} />
</TabsContent>
<TabsContent value="calendar" className="focus-visible:outline-none">
<AgendaCalendarView events={dataset.calendarEvents} range={dataset.range} />
</TabsContent>
</Tabs>
</div>
</AppShell>
)
}
function getGreetingMessage(date: Date = new Date()) {
const hour = date.getHours()
if (hour < 12) return "Bom dia"
if (hour < 18) return "Boa tarde"
return "Boa noite"
}
function formatRangeDescription(period: AgendaPeriod, range: { start: Date; end: Date }) {
if (period === "today") {
return `Hoje é ${format(range.start, "eeee, d 'de' MMMM", { locale: ptBR })}`
}
if (period === "week") {
return `Semana de ${format(range.start, "d MMM", { locale: ptBR })} a ${format(range.end, "d MMM", { locale: ptBR })}`
}
return `Mês de ${format(range.start, "MMMM 'de' yyyy", { locale: ptBR })}`
}