66 lines
2 KiB
TypeScript
66 lines
2 KiB
TypeScript
import type { Ticket } from "@/lib/schemas/ticket"
|
|
|
|
export type SlaTimerType = "response" | "solution"
|
|
export type SlaDisplayStatus = "on_track" | "at_risk" | "breached" | "met" | "n/a"
|
|
|
|
const DEFAULT_ALERT_THRESHOLD = 0.8
|
|
|
|
export function getSlaDueDate(ticket: Ticket, type: SlaTimerType): Date | null {
|
|
if (type === "response") {
|
|
return ticket.slaResponseDueAt ?? null
|
|
}
|
|
return ticket.slaSolutionDueAt ?? ticket.dueAt ?? null
|
|
}
|
|
|
|
export function getSlaDisplayStatus(ticket: Ticket, type: SlaTimerType, now: Date = new Date()): SlaDisplayStatus {
|
|
const snapshot = ticket.slaSnapshot
|
|
const dueAt = getSlaDueDate(ticket, type)
|
|
const finalStatus = type === "response" ? ticket.slaResponseStatus : ticket.slaSolutionStatus
|
|
|
|
if (!snapshot || !dueAt) {
|
|
if (finalStatus === "met" || finalStatus === "breached") {
|
|
return finalStatus
|
|
}
|
|
return "n/a"
|
|
}
|
|
|
|
if (finalStatus === "met" || finalStatus === "breached") {
|
|
return finalStatus
|
|
}
|
|
|
|
const completedAt = type === "response" ? ticket.firstResponseAt : ticket.resolvedAt
|
|
if (completedAt) {
|
|
return completedAt.getTime() <= dueAt.getTime() ? "met" : "breached"
|
|
}
|
|
|
|
const elapsed = getEffectiveElapsedMs(ticket, now)
|
|
const total = dueAt.getTime() - ticket.createdAt.getTime()
|
|
if (total <= 0) {
|
|
return now.getTime() <= dueAt.getTime() ? "on_track" : "breached"
|
|
}
|
|
|
|
if (now.getTime() > dueAt.getTime()) {
|
|
return "breached"
|
|
}
|
|
|
|
const threshold = snapshot.alertThreshold ?? DEFAULT_ALERT_THRESHOLD
|
|
const ratio = elapsed / total
|
|
if (ratio >= 1) {
|
|
return "breached"
|
|
}
|
|
if (ratio >= threshold) {
|
|
return "at_risk"
|
|
}
|
|
return "on_track"
|
|
}
|
|
|
|
function getEffectiveElapsedMs(ticket: Ticket, now: Date) {
|
|
const pausedMs = ticket.slaPausedMs ?? 0
|
|
const pausedAt = ticket.slaPausedAt ?? null
|
|
const createdAt = ticket.createdAt instanceof Date ? ticket.createdAt : new Date(ticket.createdAt)
|
|
let elapsed = now.getTime() - createdAt.getTime() - pausedMs
|
|
if (pausedAt) {
|
|
elapsed -= now.getTime() - pausedAt.getTime()
|
|
}
|
|
return Math.max(0, elapsed)
|
|
}
|