Spaces:
Paused
Paused
SOS alert queue with ack/resolve
Browse files
web/src/components/SosPanel.jsx
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export default function SosPanel({ sos, openCount, onAck, onResolve }) {
|
| 2 |
+
return (
|
| 3 |
+
<section className="panel">
|
| 4 |
+
<h2>SOS alerts {openCount > 0 && <span className="badge">{openCount}</span>}</h2>
|
| 5 |
+
{sos.length === 0 && <p className="muted small">No alerts.</p>}
|
| 6 |
+
{sos.map((a) => (
|
| 7 |
+
<div key={a.id} className={`sos-item ${a.state}`}>
|
| 8 |
+
<div>
|
| 9 |
+
<b>{a.member_name}</b>{' '}
|
| 10 |
+
<span className="muted small">{new Date(a.created_at).toLocaleTimeString()}</span>
|
| 11 |
+
<div className="muted small">
|
| 12 |
+
{a.lat != null ? `${a.lat.toFixed(5)}, ${a.lng.toFixed(5)}` : 'no fix'}
|
| 13 |
+
{a.ack_by ? ` · ack: ${a.ack_by}` : ''}
|
| 14 |
+
</div>
|
| 15 |
+
</div>
|
| 16 |
+
<div className="row">
|
| 17 |
+
{a.state === 'open' && <button className="small-btn" onClick={() => onAck(a.id)}>Ack</button>}
|
| 18 |
+
{a.state !== 'resolved' && (
|
| 19 |
+
<button className="secondary small-btn" onClick={() => onResolve(a.id)}>Resolve</button>
|
| 20 |
+
)}
|
| 21 |
+
</div>
|
| 22 |
+
</div>
|
| 23 |
+
))}
|
| 24 |
+
</section>
|
| 25 |
+
);
|
| 26 |
+
}
|