fix: align ticket timers to server clock

This commit is contained in:
Esdras Renan 2025-10-19 20:27:11 -03:00
parent 3b5676ed35
commit 090ebb9607
7 changed files with 162 additions and 17 deletions

View file

@ -1,6 +1,6 @@
"use client"
import { useEffect, useState } from "react"
import { useEffect, useRef, useState } from "react"
import { useRouter } from "next/navigation"
import { format, formatDistanceToNowStrict } from "date-fns"
import { ptBR } from "date-fns/locale"
@ -22,6 +22,7 @@ import {
} from "@/components/ui/table"
import { PrioritySelect } from "@/components/tickets/priority-select"
import { cn } from "@/lib/utils"
import { deriveServerOffset, toServerTimestamp } from "@/components/tickets/ticket-timer.utils"
const channelLabel: Record<TicketChannel, string> = {
EMAIL: "E-mail",
@ -112,6 +113,7 @@ export type TicketsTableProps = {
export function TicketsTable({ tickets }: TicketsTableProps) {
const safeTickets = tickets ?? []
const [now, setNow] = useState(() => Date.now())
const serverOffsetRef = useRef<number>(0)
const router = useRouter()
useEffect(() => {
@ -121,11 +123,25 @@ export function TicketsTable({ tickets }: TicketsTableProps) {
return () => clearInterval(interval)
}, [])
useEffect(() => {
const candidates = (tickets ?? [])
.map((ticket) => (typeof ticket.workSummary?.serverNow === "number" ? ticket.workSummary.serverNow : null))
.filter((value): value is number => value !== null)
if (candidates.length === 0) return
const latestServerNow = candidates[candidates.length - 1]
serverOffsetRef.current = deriveServerOffset({
currentOffset: serverOffsetRef.current,
localNow: Date.now(),
serverNow: latestServerNow,
})
}, [tickets])
const getWorkedMs = (ticket: Ticket) => {
const base = ticket.workSummary?.totalWorkedMs ?? 0
const activeStart = ticket.workSummary?.activeSession?.startedAt
if (activeStart instanceof Date) {
return base + Math.max(0, now - activeStart.getTime())
const alignedNow = toServerTimestamp(now, serverOffsetRef.current)
return base + Math.max(0, alignedNow - activeStart.getTime())
}
return base
}