Spaces:
Sleeping
Sleeping
| import { useEffect, useState } from "react"; | |
| import { Clock, Pause, Play } from "lucide-react"; | |
| import { cn } from "@/lib/utils"; | |
| interface CallTimerProps { | |
| startTime: Date; | |
| initialDuration?: number; | |
| isActive?: boolean; | |
| className?: string; | |
| } | |
| export function CallTimer({ startTime, initialDuration = 0, isActive = true, className }: CallTimerProps) { | |
| const [elapsed, setElapsed] = useState(initialDuration); | |
| useEffect(() => { | |
| if (!isActive) return; | |
| const interval = setInterval(() => { | |
| const now = new Date(); | |
| const diff = Math.floor((now.getTime() - new Date(startTime).getTime()) / 1000); | |
| setElapsed(diff); | |
| }, 1000); | |
| return () => clearInterval(interval); | |
| }, [startTime, isActive]); | |
| const formatTime = (totalSeconds: number): string => { | |
| const hours = Math.floor(totalSeconds / 3600); | |
| const minutes = Math.floor((totalSeconds % 3600) / 60); | |
| const seconds = totalSeconds % 60; | |
| if (hours > 0) { | |
| return `${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; | |
| } | |
| return `${minutes}:${seconds.toString().padStart(2, "0")}`; | |
| }; | |
| return ( | |
| <div | |
| className={cn( | |
| "flex flex-col items-center justify-center p-6 rounded-lg bg-card border border-card-border", | |
| className | |
| )} | |
| role="timer" | |
| aria-label={`Call duration: ${formatTime(elapsed)}`} | |
| data-testid="call-timer-widget" | |
| > | |
| <div className="flex items-center gap-2 mb-2"> | |
| <Clock className="h-5 w-5 text-muted-foreground" aria-hidden="true" /> | |
| <span className="text-sm font-medium text-muted-foreground">Call Duration</span> | |
| </div> | |
| <div className="flex items-center gap-3"> | |
| <span className="text-4xl font-mono font-semibold tracking-tight" data-testid="call-timer-display"> | |
| {formatTime(elapsed)} | |
| </span> | |
| {isActive ? ( | |
| <span className="flex items-center gap-1 text-xs text-emerald-600 dark:text-emerald-400"> | |
| <span className="relative flex h-2 w-2"> | |
| <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" /> | |
| <span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500" /> | |
| </span> | |
| Live | |
| </span> | |
| ) : ( | |
| <span className="flex items-center gap-1 text-xs text-muted-foreground"> | |
| <Pause className="h-3 w-3" /> | |
| Paused | |
| </span> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |