diff --git a/src/components/tickets/close-ticket-dialog.tsx b/src/components/tickets/close-ticket-dialog.tsx index 1403492..af3f0e9 100644 --- a/src/components/tickets/close-ticket-dialog.tsx +++ b/src/components/tickets/close-ticket-dialog.tsx @@ -107,8 +107,10 @@ type CloseTicketDraft = { shouldAdjustTime: boolean internalHours: string internalMinutes: string + internalSeconds: string externalHours: string externalMinutes: string + externalSeconds: string adjustReason: string linkedReference: string reopenWindowDays: string @@ -128,17 +130,22 @@ function applyTemplatePlaceholders(html: string, customerName?: string | null, a const splitDuration = (ms: number) => { const safeMs = Number.isFinite(ms) && ms > 0 ? ms : 0 - const totalMinutes = Math.round(safeMs / 60000) - const hours = Math.floor(totalMinutes / 60) - const minutes = totalMinutes % 60 - return { hours, minutes } + const totalSeconds = Math.floor(safeMs / 1000) + const hours = Math.floor(totalSeconds / 3600) + const minutes = Math.floor((totalSeconds % 3600) / 60) + const seconds = totalSeconds % 60 + return { hours, minutes, seconds } } const formatDurationLabel = (ms: number) => { - const { hours, minutes } = splitDuration(ms) - if (hours > 0 && minutes > 0) return `${hours}h ${minutes}min` - if (hours > 0) return `${hours}h` - return `${minutes}min` + const { hours, minutes, seconds } = splitDuration(ms) + if (hours > 0) { + return `${hours}h ${minutes.toString().padStart(2, "0")}m` + } + if (minutes > 0) { + return `${minutes}m ${seconds.toString().padStart(2, "0")}s` + } + return `${seconds}s` } const STATUS_LABELS: Record = { @@ -218,8 +225,10 @@ export function CloseTicketDialog({ const [shouldAdjustTime, setShouldAdjustTime] = useState(false) const [internalHours, setInternalHours] = useState("0") const [internalMinutes, setInternalMinutes] = useState("0") + const [internalSeconds, setInternalSeconds] = useState("0") const [externalHours, setExternalHours] = useState("0") const [externalMinutes, setExternalMinutes] = useState("0") + const [externalSeconds, setExternalSeconds] = useState("0") const [adjustReason, setAdjustReason] = useState("") const enableAdjustment = Boolean(canAdjustTime && workSummary) const [linkedReference, setLinkedReference] = useState("") @@ -277,8 +286,10 @@ export function CloseTicketDialog({ setAdjustReason("") setInternalHours("0") setInternalMinutes("0") + setInternalSeconds("0") setExternalHours("0") setExternalMinutes("0") + setExternalSeconds("0") setLinkedReference("") setLinkedTicketSelection(null) setLinkSuggestions([]) @@ -306,8 +317,10 @@ export function CloseTicketDialog({ setShouldAdjustTime(Boolean(parsed.shouldAdjustTime)) setInternalHours(parsed.internalHours ?? "0") setInternalMinutes(parsed.internalMinutes ?? "0") + setInternalSeconds(parsed.internalSeconds ?? "0") setExternalHours(parsed.externalHours ?? "0") setExternalMinutes(parsed.externalMinutes ?? "0") + setExternalSeconds(parsed.externalSeconds ?? "0") setAdjustReason(parsed.adjustReason ?? "") setLinkedReference(parsed.linkedReference ?? "") setLinkedTicketSelection(null) @@ -332,8 +345,10 @@ export function CloseTicketDialog({ shouldAdjustTime, internalHours, internalMinutes, + internalSeconds, externalHours, externalMinutes, + externalSeconds, adjustReason, linkedReference, reopenWindowDays, @@ -348,8 +363,10 @@ export function CloseTicketDialog({ draftStorageKey, externalHours, externalMinutes, + externalSeconds, internalHours, internalMinutes, + internalSeconds, linkedReference, message, reopenWindowDays, @@ -392,8 +409,10 @@ export function CloseTicketDialog({ const external = splitDuration(workSummary?.externalWorkedMs ?? 0) setInternalHours(internal.hours.toString()) setInternalMinutes(internal.minutes.toString()) + setInternalSeconds(internal.seconds.toString()) setExternalHours(external.hours.toString()) setExternalMinutes(external.minutes.toString()) + setExternalSeconds(external.seconds.toString()) }, [ open, enableAdjustment, @@ -595,6 +614,12 @@ export function CloseTicketDialog({ toast.error("Os minutos internos devem estar entre 0 e 59.") return } + const internalSecondsValue = parsePart(internalSeconds, "segundos internos") + if (internalSecondsValue === null) return + if (internalSecondsValue >= 60) { + toast.error("Os segundos internos devem estar entre 0 e 59.") + return + } const externalHoursValue = parsePart(externalHours, "horas externas") if (externalHoursValue === null) return @@ -604,9 +629,15 @@ export function CloseTicketDialog({ toast.error("Os minutos externos devem estar entre 0 e 59.") return } + const externalSecondsValue = parsePart(externalSeconds, "segundos externos") + if (externalSecondsValue === null) return + if (externalSecondsValue >= 60) { + toast.error("Os segundos externos devem estar entre 0 e 59.") + return + } - targetInternalMs = (internalHoursValue * 60 + internalMinutesValue) * 60000 - targetExternalMs = (externalHoursValue * 60 + externalMinutesValue) * 60000 + targetInternalMs = (internalHoursValue * 3600 + internalMinutesValue * 60 + internalSecondsValue) * 1000 + targetExternalMs = (externalHoursValue * 3600 + externalMinutesValue * 60 + externalSecondsValue) * 1000 trimmedReason = adjustReason.trim() if (trimmedReason.length < 5) { toast.error("Descreva o motivo do ajuste (mínimo de 5 caracteres).") @@ -716,10 +747,10 @@ export function CloseTicketDialog({ {shouldAdjustTime ? (
-
-
+
+

Tempo interno

-
+
+
+ + setInternalSeconds(event.target.value)} + disabled={isSubmitting} + /> +

Atual: {formatDurationLabel(workSummary?.internalWorkedMs ?? 0)}

-
+

Tempo externo

-
+
+
+ + setExternalSeconds(event.target.value)} + disabled={isSubmitting} + /> +

Atual: {formatDurationLabel(workSummary?.externalWorkedMs ?? 0)}

@@ -805,7 +868,7 @@ export function CloseTicketDialog({ disabled={isSubmitting} />

- Registre o motivo para fins de auditoria interna. Informe valores em minutos quando menor que 1 hora. + Registre o motivo para fins de auditoria interna.