feat: integrate hospital management module with advanced UI styling and analytics components
This commit is contained in:
218
src/pages/hospital/TeleLinkHub.tsx
Normal file
218
src/pages/hospital/TeleLinkHub.tsx
Normal file
@@ -0,0 +1,218 @@
|
||||
import React, { useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
Video,
|
||||
VideoOff,
|
||||
Mic,
|
||||
MicOff,
|
||||
PhoneOff,
|
||||
User,
|
||||
Activity,
|
||||
MessageSquare,
|
||||
ClipboardList,
|
||||
AlertCircle,
|
||||
MoreVertical,
|
||||
Shield,
|
||||
Clock,
|
||||
CheckCircle2,
|
||||
XCircle,
|
||||
MessageCircle
|
||||
} from 'lucide-react';
|
||||
import { Card } from '../../components/Common';
|
||||
|
||||
export const TeleLinkHub: React.FC = () => {
|
||||
const [activeCall, setActiveCall] = useState<any>(null);
|
||||
const [activeTab, setActiveTab] = useState<'CALL' | 'HISTORY'>('CALL');
|
||||
|
||||
const incomingRequests = [
|
||||
{ id: 'TL-101', patient: 'Rajesh Khanna', triage: 'RED', wait: '1:45', complaint: 'Cardiac Arrest', symptoms: 'Ongoing CPR, 2 shocks delivered' },
|
||||
{ id: 'TL-102', patient: 'Unknown Male', triage: 'RED', wait: '0:30', complaint: 'Potential Stroke', symptoms: 'GCS 12, unilateral weakness' },
|
||||
];
|
||||
|
||||
const callHistory = [
|
||||
{ id: 'TL-098', date: '2026-05-04', duration: '12m 45s', patient: 'Amit Shah', outcome: 'Admission Admitted', emt: 'Arjun K.' },
|
||||
{ id: 'TL-095', date: '2026-05-04', duration: '08m 20s', patient: 'Priya Verma', outcome: 'Consult Completed', emt: 'Suman R.' },
|
||||
];
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="module-content"
|
||||
>
|
||||
<div className="module-header-modern">
|
||||
<div className="title-wrap">
|
||||
<h3>TELELINK COMMAND CENTER</h3>
|
||||
<div className="live-pill">
|
||||
<span className="pulse" /> ERCP PHYSICIAN CONSOLE
|
||||
</div>
|
||||
</div>
|
||||
<div className="tab-switcher-premium">
|
||||
<button
|
||||
className={`tab-btn ${activeTab === 'CALL' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('CALL')}
|
||||
>
|
||||
ACTIVE SESSIONS
|
||||
</button>
|
||||
<button
|
||||
className={`tab-btn ${activeTab === 'HISTORY' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('HISTORY')}
|
||||
>
|
||||
CONSULT HISTORY
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{activeTab === 'CALL' ? (
|
||||
<div className="telelink-main-grid">
|
||||
{/* Call Queue */}
|
||||
<div className="call-queue-panel">
|
||||
<div className="panel-header-mini">
|
||||
<h4>INCOMING REQUESTS</h4>
|
||||
<span className="count-badge">{incomingRequests.length}</span>
|
||||
</div>
|
||||
<div className="queue-list">
|
||||
{incomingRequests.map(req => (
|
||||
<div key={req.id} className={`queue-item triage-${req.triage.toLowerCase()}`}>
|
||||
<div className="q-header">
|
||||
<span className="q-id">{req.id}</span>
|
||||
<span className="q-wait"><Clock size={12} /> {req.wait}</span>
|
||||
</div>
|
||||
<div className="q-body">
|
||||
<div className="q-patient">{req.patient}</div>
|
||||
<div className="q-complaint">{req.complaint}</div>
|
||||
</div>
|
||||
<div className="q-actions">
|
||||
<button className="q-btn accept" onClick={() => setActiveCall(req)}>ACCEPT</button>
|
||||
<button className="q-btn decline">DECLINE</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Active Call Surface */}
|
||||
<div className="call-surface-panel-premium">
|
||||
<div className="surface-glass-glow" />
|
||||
|
||||
{activeCall ? (
|
||||
<div className="active-call-grid">
|
||||
<div className="video-workspace">
|
||||
<div className="video-feed-main">
|
||||
<div className="feed-header-overlay">
|
||||
<div className="secure-badge">
|
||||
<Shield size={14} /> 256-BIT ENCRYPTED
|
||||
</div>
|
||||
<div className="call-duration">12:45</div>
|
||||
</div>
|
||||
|
||||
<div className="video-placeholder-premium">
|
||||
<div className="video-pulse-icon">
|
||||
<Video size={48} />
|
||||
</div>
|
||||
<p>INITIALIZING SECURE VIDEO FEED...</p>
|
||||
<div className="patient-id-overlay">
|
||||
<span className="p-triage" data-triage={activeCall.triage.toLowerCase()}>{activeCall.triage}</span>
|
||||
<div className="p-name-stack">
|
||||
<span className="name">{activeCall.patient}</span>
|
||||
<span className="id">CASE: {activeCall.id}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="video-actions-floating">
|
||||
<button className="v-float-btn"><Mic size={20} /></button>
|
||||
<button className="v-float-btn active"><Video size={20} /></button>
|
||||
<button className="v-float-btn end-session" onClick={() => setActiveCall(null)}><PhoneOff size={20} /></button>
|
||||
<div className="v-divider-vertical" />
|
||||
<button className="v-float-btn"><MessageCircle size={20} /></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="clinical-data-rail">
|
||||
<div className="rail-section">
|
||||
<div className="rail-head">
|
||||
<Activity size={16} /> <h4>LIVE VITALS</h4>
|
||||
</div>
|
||||
<div className="vitals-mini-grid">
|
||||
<div className="v-stat-card">
|
||||
<label>HEART RATE</label>
|
||||
<div className="val">102<small>BPM</small></div>
|
||||
</div>
|
||||
<div className="v-stat-card">
|
||||
<label>SPO2</label>
|
||||
<div className="val">94%</div>
|
||||
</div>
|
||||
<div className="v-stat-card">
|
||||
<label>BP</label>
|
||||
<div className="val">130/85</div>
|
||||
</div>
|
||||
<div className="v-stat-card warning">
|
||||
<label>TEMP</label>
|
||||
<div className="val">101.4<small>°F</small></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rail-section grow">
|
||||
<div className="rail-head">
|
||||
<ClipboardList size={16} /> <h4>TELE-CONSULT NOTES</h4>
|
||||
</div>
|
||||
<textarea className="clinical-input" placeholder="Type clinical advice, prescriptions, or observations..." />
|
||||
<button className="commit-btn">COMMIT TO EPCR</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="idle-surface-placeholder">
|
||||
<div className="idle-icon-wrap">
|
||||
<VideoOff size={64} />
|
||||
<div className="idle-ring" />
|
||||
</div>
|
||||
<h3>READY FOR UPLINK</h3>
|
||||
<p>Select a pending triage request from the queue to bridge TeleLink session</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="history-panel-full">
|
||||
<table className="staff-table-premium">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Session ID & Date</th>
|
||||
<th>Patient</th>
|
||||
<th>Duration</th>
|
||||
<th>EMT / Field Provider</th>
|
||||
<th>Clinical Outcome</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{callHistory.map(h => (
|
||||
<tr key={h.id}>
|
||||
<td>
|
||||
<div style={{ fontWeight: 700 }}>{h.id}</div>
|
||||
<div style={{ fontSize: '0.75rem', color: 'var(--text-secondary)' }}>{h.date}</div>
|
||||
</td>
|
||||
<td>{h.patient}</td>
|
||||
<td>{h.duration}</td>
|
||||
<td>{h.emt}</td>
|
||||
<td>
|
||||
<span className="status-badge" style={{ background: 'rgba(16, 185, 129, 0.1)', color: 'var(--accent-green)' }}>
|
||||
{h.outcome}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<button className="tag-btn"><ClipboardList size={14} /></button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user