dynamic graph
This commit is contained in:
parent
a606796d9e
commit
5e029ff99c
17 changed files with 1707 additions and 569 deletions
186
components/bed-pressure/AlertsPanel.tsx
Normal file
186
components/bed-pressure/AlertsPanel.tsx
Normal file
|
@ -0,0 +1,186 @@
|
|||
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>
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue