TypeScript · 2837 bytes Raw Blame History
1 import React, { useEffect, useState } from 'react';
2
3 interface TimerDisplayProps {
4 gameTreeId: number | null;
5 sessionId: number | null;
6 onTimerExpire?: () => void;
7 }
8
9 const TimerDisplay: React.FC<TimerDisplayProps> = ({
10 gameTreeId,
11 sessionId,
12 onTimerExpire
13 }) => {
14 const [timerData, setTimerData] = useState({
15 remaining: 60,
16 warningLevel: null as string | null,
17 expired: false,
18 paused: false
19 });
20
21 useEffect(() => {
22 if (!gameTreeId) return;
23
24 const checkTimer = async () => {
25 try {
26 const response = await fetch(
27 `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api'}/trees/filesystem-trees/${gameTreeId}/timer_status/`
28 );
29
30 if (response.ok) {
31 const data = await response.json();
32 setTimerData({
33 remaining: data.remaining,
34 warningLevel: data.warning_level,
35 expired: data.expired,
36 paused: data.paused
37 });
38
39 // Notify parent if timer expired
40 if (data.expired && onTimerExpire) {
41 onTimerExpire();
42 }
43 }
44 } catch (error) {
45 console.error('Failed to check timer:', error);
46 }
47 };
48
49 // Check immediately
50 checkTimer();
51
52 // Then check every second
53 const interval = setInterval(checkTimer, 1000);
54
55 return () => clearInterval(interval);
56 }, [gameTreeId, sessionId, onTimerExpire]);
57
58 // Determine display based on warning level
59 let borderColor = 'border-green-500';
60 let textColor = 'text-green-400';
61 let statusMessage = null;
62 let pulseAnimation = '';
63
64 if (timerData.expired || timerData.remaining <= 0) {
65 borderColor = 'border-red-600';
66 textColor = 'text-red-600';
67 statusMessage = 'Escaped!';
68 } else if (timerData.warningLevel === 'critical') {
69 borderColor = 'border-red-500';
70 textColor = 'text-red-400';
71 statusMessage = 'Escaping!';
72 pulseAnimation = 'animate-pulse';
73 } else if (timerData.warningLevel === 'alert') {
74 borderColor = 'border-orange-500';
75 textColor = 'text-orange-400';
76 statusMessage = 'Burrowing!';
77 } else if (timerData.warningLevel === 'warning') {
78 borderColor = 'border-yellow-500';
79 textColor = 'text-yellow-400';
80 statusMessage = 'Alert!';
81 }
82
83 return (
84 <div className={`bg-black/80 backdrop-blur-sm border ${borderColor} rounded-lg p-3 shadow-2xl ${pulseAnimation}`}>
85 <div className={`${textColor} font-terminal text-sm`}>
86 <div className="flex items-center justify-between">
87 <span>Time:</span>
88 <span className="font-bold">{Math.max(0, timerData.remaining)}s</span>
89 </div>
90 {statusMessage && (
91 <div className="text-center text-xs mt-1">{statusMessage}</div>
92 )}
93 </div>
94 </div>
95 );
96 };
97
98 export default TimerDisplay;