m2-inno-bedpressure/components/bed-pressure/AlertsPanel.tsx
2025-06-21 12:55:27 +07:00

186 lines
No EOL
7.1 KiB
TypeScript

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { AlertTriangle, VolumeX, Clock, CheckCircle } from "lucide-react"
import { useBedPressureStore } from "@/stores/bedPressureStore"
import { useEffect } from "react"
export function AlertsPanel() {
const {
alerts,
activeAlarms,
alarmManager,
acknowledgeAlarm,
silenceAlarm,
silenceAllAlarms
} = useBedPressureStore()
// Update active alarms periodically
useEffect(() => {
const interval = setInterval(() => {
// The store will handle updating alarms automatically
}, 1000)
return () => clearInterval(interval)
}, [alarmManager])
const handleAcknowledge = (alarmId: string) => {
acknowledgeAlarm(alarmId)
}
const handleSilence = (alarmId: string) => {
silenceAlarm(alarmId, 300000) // Silence for 5 minutes
}
const handleSilenceAll = () => {
silenceAllAlarms(300000) // Silence all for 5 minutes
}
const getAlarmIcon = (type: 'warning' | 'alarm') => {
return type === 'alarm' ? (
<AlertTriangle className="w-4 h-4 text-red-600 animate-pulse" />
) : (
<AlertTriangle className="w-4 h-4 text-yellow-600" />
)
}
const getAlarmBgColor = (type: 'warning' | 'alarm', silenced: boolean) => {
if (silenced) return "bg-gray-100 border-gray-300"
return type === 'alarm' ? "bg-red-50 border-red-200" : "bg-yellow-50 border-yellow-200"
}
const hasActiveAlarms = activeAlarms.some(alarm => !alarm.silenced)
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle className="flex items-center gap-2">
<AlertTriangle className={`w-5 h-5 ${hasActiveAlarms ? "text-red-600 animate-pulse" : "text-gray-400"}`} />
Active Alarms ({activeAlarms.length})
</CardTitle>
{activeAlarms.length > 0 && (
<Button
variant="outline"
size="sm"
onClick={handleSilenceAll}
className="text-orange-600 hover:text-orange-700"
>
<VolumeX className="w-4 h-4 mr-1" />
Silence All
</Button>
)}
</div>
</CardHeader>
<CardContent>
<div className="space-y-3 max-h-80 overflow-y-auto">
{activeAlarms.length === 0 ? (
<div className="text-center py-8">
<CheckCircle className="w-12 h-12 text-green-500 mx-auto mb-2" />
<p className="text-sm text-gray-500">No active alarms</p>
<p className="text-xs text-gray-400">System monitoring normally</p>
</div>
) : (
activeAlarms.map((alarm) => (
<div
key={alarm.id}
className={`p-3 rounded-lg border ${getAlarmBgColor(alarm.type, alarm.silenced)}`}
>
<div className="flex items-start justify-between">
<div className="flex items-start gap-3 flex-1">
{getAlarmIcon(alarm.type)}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<p className={`text-sm font-medium ${
alarm.type === 'alarm' ? 'text-red-800' : 'text-yellow-800'
}`}>
{alarm.sensorLabel}
</p>
<span className={`text-xs px-2 py-1 rounded ${
alarm.type === 'alarm'
? 'bg-red-100 text-red-700'
: 'bg-yellow-100 text-yellow-700'
}`}>
{alarm.type.toUpperCase()}
</span>
{alarm.silenced && (
<span className="text-xs px-2 py-1 rounded bg-gray-100 text-gray-600 flex items-center gap-1">
<VolumeX className="w-3 h-3" />
SILENCED
</span>
)}
</div>
<p className={`text-xs mb-2 ${
alarm.type === 'alarm' ? 'text-red-700' : 'text-yellow-700'
}`}>
Value: {alarm.value.toFixed(0)} (Threshold: {alarm.threshold})
</p>
<div className="flex items-center gap-2 text-xs text-gray-600">
<Clock className="w-3 h-3" />
<span>{alarm.time}</span>
{alarm.acknowledged && (
<span className="text-green-600 flex items-center gap-1">
<CheckCircle className="w-3 h-3" />
ACK
</span>
)}
{alarm.silenced && alarm.silencedUntil && (
<span className="text-gray-500">
Until {new Date(alarm.silencedUntil).toLocaleTimeString()}
</span>
)}
</div>
</div>
</div>
<div className="flex flex-col gap-1 ml-2">
{!alarm.acknowledged && (
<Button
variant="outline"
size="sm"
onClick={() => handleAcknowledge(alarm.id)}
className="text-xs h-6 px-2"
>
ACK
</Button>
)}
{!alarm.silenced && (
<Button
variant="outline"
size="sm"
onClick={() => handleSilence(alarm.id)}
className="text-xs h-6 px-2 text-orange-600 hover:text-orange-700"
>
<VolumeX className="w-3 h-3" />
</Button>
)}
</div>
</div>
</div>
))
)}
</div>
{/* Legacy Alerts Section */}
{alerts.length > 0 && (
<div className="mt-6 pt-4 border-t">
<h4 className="text-sm font-medium text-gray-700 mb-3">Recent Alerts</h4>
<div className="space-y-2 max-h-32 overflow-y-auto">
{alerts.slice(0, 3).map((alert) => (
<div
key={alert.id}
className="flex items-start gap-2 p-2 bg-blue-50 rounded border border-blue-200"
>
<AlertTriangle className="w-3 h-3 text-blue-600 mt-0.5 flex-shrink-0" />
<div className="flex-1 min-w-0">
<p className="text-xs font-medium text-blue-800">{alert.message}</p>
<p className="text-xs text-blue-600">{alert.time}</p>
</div>
</div>
))}
</div>
</div>
)}
</CardContent>
</Card>
)
}