1 import { useState, useEffect } from "react";
2 import { Button } from "@/components/ui/button";
3 import {
4 Wrench,
5 AlertTriangle,
6 ShieldCheck,
7 Download,
8 HelpCircle,
9 X,
10 Zap,
11 Sparkles,
12 Timer,
13 ChevronRight,
14 Activity,
15 Cpu,
16 Layers,
17 CheckCircle2,
18 Volume2,
19 Maximize2,
20 ExternalLink,
21 Flame,
22 Smartphone
23 } from "lucide-react";
24 import { useLocation } from "wouter";
25 import { motion, AnimatePresence } from "framer-motion";
26 import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
27 import { Badge } from "@/components/ui/badge";
28
29 export default function FloatingActionButton() {
30 const [isExpanded, setIsExpanded] = useState(false);
31 const [, setLocation] = useLocation();
32
33 // Active interactive modal state: "emergency" | "safety" | "rails" | null
34 const [activeModal, setActiveModal] = useState<"emergency" | "safety" | "rails" | null>(null);
35
36 // Emergency countdown timer state
37 const [countdown, setCountdown] = useState<number | null>(null);
38 const [timerRunning, setTimerRunning] = useState(false);
39
40 useEffect(() => {
41 let interval: NodeJS.Timeout;
42 if (timerRunning && countdown !== null && countdown > 0) {
43 interval = setInterval(() => {
44 setCountdown((prev) => (prev !== null && prev > 0 ? prev - 1 : 0));
45 }, 1000);
46 } else if (countdown === 0) {
47 setTimerRunning(false);
48 }
49 return () => clearInterval(interval);
50 }, [timerRunning, countdown]);
51
52 const startEmergencyTimer = () => {
53 setCountdown(15);
54 setTimerRunning(true);
55 };
56
57 const resetEmergencyTimer = () => {
58 setCountdown(15);
59 setTimerRunning(false);
60 };
61
62 const quickActions = [
63 {
64 id: "emergency",
65 label: "Emergency Discharge",
66 tag: "HARD RESET",
67 desc: "15s EC drain & battery isolation protocol",
68 icon: AlertTriangle,
69 glowColor: "from-amber-500/20 to-orange-500/10",
70 borderColor: "border-amber-500/30 hover:border-amber-500/70 group-hover:bg-amber-500/10",
71 iconBg: "bg-amber-500/15 text-amber-500 border-amber-500/30",
72 badgeColor: "bg-amber-500/20 text-amber-600 dark:text-amber-400 border-amber-500/30",
73 action: () => {
74 setActiveModal("emergency");
75 setIsExpanded(false);
76 setCountdown(15);
77 setTimerRunning(false);
78 },
79 },
80 {
81 id: "rails",
82 label: "Voltage Rail Pinouts",
83 tag: "MULTIMETER",
84 desc: "Instant +19V, +3.3V, +5V standby test points",
85 icon: Activity,
86 glowColor: "from-cyan-500/20 to-blue-500/10",
87 borderColor: "border-cyan-500/30 hover:border-cyan-500/70 group-hover:bg-cyan-500/10",
88 iconBg: "bg-cyan-500/15 text-cyan-500 border-cyan-500/30",
89 badgeColor: "bg-cyan-500/20 text-cyan-600 dark:text-cyan-400 border-cyan-500/30",
90 action: () => {
91 setActiveModal("rails");
92 setIsExpanded(false);
93 },
94 },
95 {
96 id: "safety",
97 label: "Torque & ESD Standards",
98 tag: "BENCH SPECS",
99 desc: "0.25 Nm limits, PTM7950 & thermal pads",
100 icon: ShieldCheck,
101 glowColor: "from-emerald-500/20 to-teal-500/10",
102 borderColor: "border-emerald-500/30 hover:border-emerald-500/70 group-hover:bg-emerald-500/10",
103 iconBg: "bg-emerald-500/15 text-emerald-500 border-emerald-500/30",
104 badgeColor: "bg-emerald-500/20 text-emerald-600 dark:text-emerald-400 border-emerald-500/30",
105 action: () => {
106 setActiveModal("safety");
107 setIsExpanded(false);
108 },
109 },
110 {
111 id: "tools",
112 label: "52 Verified Bench Tools",
113 tag: "SOFTWARE HUB",
114 desc: "FurMark 2, MemTest86, DDU, Rufus & OCCT",
115 icon: Download,
116 glowColor: "from-blue-500/20 to-indigo-500/10",
117 borderColor: "border-blue-500/30 hover:border-blue-500/70 group-hover:bg-blue-500/10",
118 iconBg: "bg-blue-500/15 text-blue-500 border-blue-500/30",
119 badgeColor: "bg-blue-500/20 text-blue-600 dark:text-blue-400 border-blue-500/30",
120 action: () => {
121 setLocation("/software-tools");
122 setIsExpanded(false);
123 },
124 },
125 {
126 id: "troubleshoot",
127 label: "Diagnostic Flowcharts",
128 tag: "TRIAGE",
129 desc: "No POST, 3-Beep codes & BSOD protocols",
130 icon: Zap,
131 glowColor: "from-purple-500/20 to-pink-500/10",
132 borderColor: "border-purple-500/30 hover:border-purple-500/70 group-hover:bg-purple-500/10",
133 iconBg: "bg-purple-500/15 text-purple-500 border-purple-500/30",
134 badgeColor: "bg-purple-500/20 text-purple-600 dark:text-purple-400 border-purple-500/30",
135 action: () => {
136 setLocation("/troubleshooting");
137 setIsExpanded(false);
138 },
139 },
140 {
141 id: "android-zip",
142 label: "Android Studio Project",
143 tag: "GRADLE • APK",
144 desc: "Download complete native Android Studio .ZIP",
145 icon: Smartphone,
146 glowColor: "from-emerald-500/20 to-green-500/10",
147 borderColor: "border-emerald-500/30 hover:border-emerald-500/70 group-hover:bg-emerald-500/10",
148 iconBg: "bg-emerald-500/15 text-emerald-500 border-emerald-500/30",
149 badgeColor: "bg-emerald-500/20 text-emerald-600 dark:text-emerald-400 border-emerald-500/30",
150 action: () => {
151 setLocation("/downloads");
152 setIsExpanded(false);
153 },
154 },
155 ];
156
157 return (
158 <>
159 <div className="fixed bottom-34 sm:bottom-22 right-4 sm:right-6 z-40 no-print">
160 <div className="relative">
161
162 {/* Fancy Pop-Out Menu Card */}
163 <AnimatePresence>
164 {isExpanded && (
165 <motion.div
166 initial={{ opacity: 0, scale: 0.88, y: 20, transformOrigin: "bottom right" }}
167 animate={{ opacity: 1, scale: 1, y: 0 }}
168 exit={{ opacity: 0, scale: 0.88, y: 20 }}
169 transition={{ type: "spring", stiffness: 350, damping: 25 }}
170 className="absolute bottom-15 right-0 w-[310px] sm:w-[360px] rounded-3xl bg-card/95 backdrop-blur-3xl border border-primary/20 shadow-[0_20px_60px_-15px_rgba(0,0,0,0.5)] overflow-hidden"
171 >
172 {/* HUD Header Banner */}
173 <div className="relative p-3.5 bg-gradient-to-r from-primary/20 via-primary/10 to-transparent border-b border-border/50 flex items-center justify-between">
174 <div className="flex items-center gap-2.5">
175 <div className="h-8 w-8 rounded-xl bg-primary text-primary-foreground flex items-center justify-center shadow-md shadow-primary/20">
176 <Sparkles className="h-4 w-4 animate-pulse" />
177 </div>
178 <div>
179 <div className="text-xs font-black tracking-wider uppercase text-foreground flex items-center gap-1.5">
180 Quick Bench HUD
181 <span className="inline-block h-1.5 w-1.5 rounded-full bg-emerald-500 animate-ping" />
182 </div>
183 <div className="text-[10px] text-muted-foreground font-mono">
184 STANDBY • 6 BENCH TOOLS
185 </div>
186 </div>
187 </div>
188
189 <button
190 onClick={() => setIsExpanded(false)}
191 className="h-7 w-7 rounded-lg hover:bg-muted/80 flex items-center justify-center text-muted-foreground hover:text-foreground transition-colors"
192 >
193 <X className="h-4 w-4" />
194 </button>
195 </div>
196
197 {/* Staggered Action Cards */}
198 <div className="p-2.5 space-y-2 max-h-[380px] overflow-y-auto">
199 {quickActions.map((item, idx) => {
200 const Icon = item.icon;
201 return (
202 <motion.button
203 key={item.id}
204 initial={{ opacity: 0, x: 15 }}
205 animate={{ opacity: 1, x: 0 }}
206 transition={{ delay: idx * 0.04, duration: 0.2 }}
207 onClick={item.action}
208 className={`w-full group relative p-2.5 rounded-2xl border ${item.borderColor} bg-gradient-to-r ${item.glowColor} hover:shadow-lg transition-all duration-200 text-left flex items-center gap-3 overflow-hidden cursor-pointer`}
209 >
210 {/* Icon Pod */}
211 <div className={`h-10 w-10 rounded-xl border flex items-center justify-center shrink-0 shadow-xs ${item.iconBg} transition-transform group-hover:scale-110 group-hover:rotate-3`}>
212 <Icon className="h-5 w-5" />
213 </div>
214
215 {/* Text Info */}
216 <div className="flex-1 min-w-0">
217 <div className="flex items-center justify-between gap-1 mb-0.5">
218 <span className="text-xs font-bold text-foreground group-hover:text-primary transition-colors truncate">
219 {item.label}
220 </span>
221 <span className={`text-[9px] font-mono font-bold px-1.5 py-0.2 rounded-md border ${item.badgeColor}`}>
222 {item.tag}
223 </span>
224 </div>
225 <p className="text-[10.5px] text-muted-foreground line-clamp-1 group-hover:text-foreground/80 transition-colors">
226 {item.desc}
227 </p>
228 </div>
229
230 <ChevronRight className="h-4 w-4 text-muted-foreground group-hover:text-primary group-hover:translate-x-0.5 transition-all shrink-0" />
231 </motion.button>
232 );
233 })}
234 </div>
235
236 {/* Bottom Status Ticker */}
237 <div className="px-3.5 py-2 bg-muted/40 border-t border-border/40 flex items-center justify-between text-[10px] text-muted-foreground font-mono">
238 <span>SAFETY INTERLOCK: ACTIVE</span>
239 <span className="text-emerald-500 font-bold">READY TO DEPLOY</span>
240 </div>
241 </motion.div>
242 )}
243 </AnimatePresence>
244
245 {/* Fancy Floating Trigger Bubble */}
246 <motion.button
247 whileHover={{ scale: 1.08 }}
248 whileTap={{ scale: 0.94 }}
249 onClick={() => setIsExpanded(!isExpanded)}
250 className={`relative h-12 w-12 sm:h-13 sm:w-13 rounded-2xl border flex items-center justify-center transition-all duration-300 shadow-xl group cursor-pointer ${
251 isExpanded
252 ? "bg-primary text-primary-foreground border-primary shadow-primary/30"
253 : "bg-card/90 hover:bg-card text-foreground border-border/70 hover:border-primary/50 shadow-glass"
254 }`}
255 title="Quick Bench Actions & HUD"
256 >
257 {/* Animated Ambient Ring / Glow */}
258 {!isExpanded && (
259 <span className="absolute -inset-0.5 rounded-2xl bg-gradient-to-r from-primary/40 to-amber-500/40 opacity-75 blur-xs group-hover:opacity-100 transition-opacity -z-10 animate-pulse" />
260 )}
261
262 {isExpanded ? (
263 <X className="h-5 w-5 transition-transform rotate-90 duration-200" />
264 ) : (
265 <div className="relative">
266 <Wrench className="h-5 w-5 text-primary group-hover:rotate-45 transition-transform duration-300" />
267 <span className="absolute -top-1 -right-1 h-2 w-2 rounded-full bg-amber-500 border border-background" />
268 </div>
269 )}
270 </motion.button>
271 </div>
272 </div>
273
274 {/* 1. Emergency Discharge Interactive Modal */}
275 <Dialog open={activeModal === "emergency"} onOpenChange={(open) => !open && setActiveModal(null)}>
276 <DialogContent className="max-w-md rounded-3xl border-amber-500/30 bg-card/95 backdrop-blur-2xl">
277 <DialogHeader>
278 <div className="flex items-center gap-2.5 mb-1">
279 <div className="p-2 rounded-xl bg-amber-500/20 text-amber-500 border border-amber-500/30">
280 <AlertTriangle className="h-5 w-5" />
281 </div>
282 <div>
283 <DialogTitle className="text-lg font-extrabold text-foreground">Emergency Force Discharge</DialogTitle>
284 <DialogDescription className="text-xs text-muted-foreground">Hard Embedded Controller (EC) Reset & Power Rail Drain</DialogDescription>
285 </div>
286 </div>
287 </DialogHeader>
288
289 <div className="space-y-4 pt-2">
290 {/* Interactive 15-Second Timer Pod */}
291 <div className="p-4 rounded-2xl bg-amber-500/10 border border-amber-500/30 text-center space-y-3">
292 <div className="text-3xl font-black font-mono text-amber-500 flex items-center justify-center gap-2">
293 <Timer className="h-7 w-7" />
294 {countdown !== null ? `${countdown}s` : "15s"}
295 </div>
296 <p className="text-xs text-muted-foreground max-w-xs mx-auto">
297 {countdown === 0 ? (
298 <span className="text-emerald-500 font-bold flex items-center justify-center gap-1">
299 <CheckCircle2 className="h-4 w-4" /> Capacitors discharged! EC is hard-reset.
300 </span>
301 ) : (
302 "Firmly press and hold the power button down during this countdown."
303 )}
304 </p>
305
306 <div className="flex justify-center gap-2">
307 <Button
308 onClick={startEmergencyTimer}
309 disabled={timerRunning}
310 className="bg-amber-500 hover:bg-amber-600 text-white rounded-xl text-xs font-bold"
311 >
312 {timerRunning ? "Timing (Hold Down)..." : "Start 15s Hold Timer"}
313 </Button>
314 <Button
315 variant="outline"
316 onClick={resetEmergencyTimer}
317 className="rounded-xl text-xs"
318 >
319 Reset
320 </Button>
321 </div>
322 </div>
323
324 {/* Checklist */}
325 <div className="space-y-2">
326 <div className="text-xs font-bold text-foreground">3-Step Bench Safe Sequence:</div>
327 <div className="p-2.5 rounded-xl bg-muted/40 border border-border/40 space-y-1.5 text-xs text-muted-foreground">
328 <div className="flex items-start gap-2">
329 <span className="font-mono font-bold text-amber-500">01.</span>
330 <span><strong>Disconnect AC Power:</strong> Unplug barrel jack and USB-C Type-C chargers immediately.</span>
331 </div>
332 <div className="flex items-start gap-2">
333 <span className="font-mono font-bold text-amber-500">02.</span>
334 <span><strong>Isolate Internal Battery:</strong> Remove bottom panel and pull the high-current battery molex header.</span>
335 </div>
336 <div className="flex items-start gap-2">
337 <span className="font-mono font-bold text-amber-500">03.</span>
338 <span><strong>Drain Residual Charge:</strong> Hold power button for 15s to drain filter capacitors before probing.</span>
339 </div>
340 </div>
341 </div>
342 </div>
343 </DialogContent>
344 </Dialog>
345
346 {/* 2. Standby Voltage Rail Quick Reference Modal */}
347 <Dialog open={activeModal === "rails"} onOpenChange={(open) => !open && setActiveModal(null)}>
348 <DialogContent className="max-w-lg rounded-3xl border-cyan-500/30 bg-card/95 backdrop-blur-2xl">
349 <DialogHeader>
350 <div className="flex items-center gap-2.5 mb-1">
351 <div className="p-2 rounded-xl bg-cyan-500/20 text-cyan-500 border border-cyan-500/30">
352 <Activity className="h-5 w-5" />
353 </div>
354 <div>
355 <DialogTitle className="text-lg font-extrabold text-foreground">Multimeter Power Rail Cheat-Sheet</DialogTitle>
356 <DialogDescription className="text-xs text-muted-foreground">Nominal voltages, tolerances, and typical board test points</DialogDescription>
357 </div>
358 </div>
359 </DialogHeader>
360
361 <div className="space-y-3 pt-2">
362 <div className="grid grid-cols-1 sm:grid-cols-2 gap-2.5">
363 {[
364 { rail: "+19.0V / +20.0V", name: "+DC_IN / VBUS", tolerance: "±5%", note: "Primary DC input MOSFETs (PQ101/PQ102)" },
365 { rail: "+3.3V_ALW", name: "Standby 3.3V Always", tolerance: "±2%", note: "Powers Super I/O EC and BIOS chip pin 8" },
366 { rail: "+5.0V_ALW", name: "Standby 5.0V Always", tolerance: "±2%", note: "Powers USB 5V lines & 5V regulator coil" },
367 { rail: "+1.8V_PRIM", name: "PCH / SoC Standby", tolerance: "±3%", note: "Chipset logic & initial power sequencer" },
368 { rail: "+1.2V / +1.1V", name: "DDR4 / DDR5 VDD", tolerance: "±1.5%", note: "RAM power rail inductor (PL501)" },
369 { rail: "+0.85V - +1.2V", name: "VCORE / VGPU", tolerance: "±1%", note: "CPU/GPU active state core switching VRMs" },
370 ].map((r, idx) => (
371 <div key={idx} className="p-3 rounded-2xl bg-muted/40 border border-border/50 space-y-1">
372 <div className="flex items-center justify-between">
373 <span className="font-mono font-bold text-sm text-cyan-600 dark:text-cyan-400">{r.rail}</span>
374 <Badge variant="outline" className="text-[10px] font-mono border-cyan-500/30">{r.tolerance}</Badge>
375 </div>
376 <div className="text-xs font-semibold text-foreground">{r.name}</div>
377 <div className="text-[10.5px] text-muted-foreground">{r.note}</div>
378 </div>
379 ))}
380 </div>
381
382 <div className="p-3 rounded-xl bg-cyan-500/10 border border-cyan-500/20 text-xs text-muted-foreground flex items-center gap-2">
383 <Sparkles className="h-4 w-4 text-cyan-500 shrink-0" />
384 <span><strong>Ground Reference:</strong> Clip black multimeter lead to copper chassis standoff or USB shield.</span>
385 </div>
386 </div>
387 </DialogContent>
388 </Dialog>
389
390 {/* 3. Torque & ESD Safety Standards Modal */}
391 <Dialog open={activeModal === "safety"} onOpenChange={(open) => !open && setActiveModal(null)}>
392 <DialogContent className="max-w-md rounded-3xl border-emerald-500/30 bg-card/95 backdrop-blur-2xl">
393 <DialogHeader>
394 <div className="flex items-center gap-2.5 mb-1">
395 <div className="p-2 rounded-xl bg-emerald-500/20 text-emerald-500 border border-emerald-500/30">
396 <ShieldCheck className="h-5 w-5" />
397 </div>
398 <div>
399 <DialogTitle className="text-lg font-extrabold text-foreground">Torque & Thermal Bench Standards</DialogTitle>
400 <DialogDescription className="text-xs text-muted-foreground">Certified technician tightening specifications & thermal protocols</DialogDescription>
401 </div>
402 </div>
403 </DialogHeader>
404
405 <div className="space-y-3 pt-2">
406 <div className="space-y-2">
407 <div className="text-xs font-bold text-foreground">Standard Torque Specifications:</div>
408 <div className="grid grid-cols-2 gap-2 text-xs">
409 <div className="p-2.5 rounded-xl bg-muted/40 border border-border/40">
410 <div className="font-mono font-bold text-emerald-500 text-sm">0.25 – 0.30 Nm</div>
411 <div className="font-semibold text-foreground mt-0.5">CPU/GPU Heatsink</div>
412 <div className="text-[10px] text-muted-foreground">Diagonal sequence (1→2→3→4)</div>
413 </div>
414 <div className="p-2.5 rounded-xl bg-muted/40 border border-border/40">
415 <div className="font-mono font-bold text-emerald-500 text-sm">0.18 – 0.20 Nm</div>
416 <div className="font-semibold text-foreground mt-0.5">M.2 NVMe & Wi-Fi</div>
417 <div className="text-[10px] text-muted-foreground">Prevents PCB trace fracturing</div>
418 </div>
419 </div>
420 </div>
421
422 <div className="p-3 rounded-2xl bg-emerald-500/10 border border-emerald-500/30 space-y-1.5 text-xs text-muted-foreground">
423 <div className="font-bold text-emerald-600 dark:text-emerald-400 flex items-center gap-1.5">
424 <Flame className="h-4 w-4" /> Recommended Thermal Interface:
425 </div>
426 <div>• <strong>Honeywell PTM7950:</strong> 0.25mm phase change pad on bare dies (no pump-out effect).</div>
427 <div>• <strong>K5 Pro Viscous Paste:</strong> For uneven VRAM and MOSFET gap replacement (0.5–2.0mm).</div>
428 </div>
429 </div>
430 </DialogContent>
431 </Dialog>
432 </>
433 );
434 }