mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
feat(kanban): Add count-up timer component for in-progress cards
- Create CountUpTimer component that displays elapsed time in MM:SS format - Timer starts counting from when a card moves to in_progress status - Shows timer on running cards (purple) and idle in_progress cards (yellow) - Updates every second to show current elapsed time 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
63
app/src/components/ui/count-up-timer.tsx
Normal file
63
app/src/components/ui/count-up-timer.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { Clock } from "lucide-react";
|
||||
|
||||
interface CountUpTimerProps {
|
||||
startedAt: string; // ISO timestamp string
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats elapsed time in MM:SS format
|
||||
* @param seconds - Total elapsed seconds
|
||||
* @returns Formatted string like "00:00", "01:30", "59:59", etc.
|
||||
*/
|
||||
function formatElapsedTime(seconds: number): string {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = seconds % 60;
|
||||
|
||||
const paddedMinutes = minutes.toString().padStart(2, "0");
|
||||
const paddedSeconds = remainingSeconds.toString().padStart(2, "0");
|
||||
|
||||
return `${paddedMinutes}:${paddedSeconds}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* CountUpTimer component that displays elapsed time since a given start time
|
||||
* Updates every second to show the current elapsed time in MM:SS format
|
||||
*/
|
||||
export function CountUpTimer({ startedAt, className = "" }: CountUpTimerProps) {
|
||||
const [elapsedSeconds, setElapsedSeconds] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
// Calculate initial elapsed time
|
||||
const startTime = new Date(startedAt).getTime();
|
||||
|
||||
const calculateElapsed = () => {
|
||||
const now = Date.now();
|
||||
const elapsed = Math.floor((now - startTime) / 1000);
|
||||
return Math.max(0, elapsed); // Ensure non-negative
|
||||
};
|
||||
|
||||
// Set initial value
|
||||
setElapsedSeconds(calculateElapsed());
|
||||
|
||||
// Update every second
|
||||
const interval = setInterval(() => {
|
||||
setElapsedSeconds(calculateElapsed());
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [startedAt]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center gap-1 text-xs text-muted-foreground ${className}`}
|
||||
data-testid="count-up-timer"
|
||||
>
|
||||
<Clock className="w-3 h-3" />
|
||||
<span data-testid="timer-display">{formatElapsedTime(elapsedSeconds)}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user