style: convert UI palette to clean clinical hospital theme
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Mic, MicOff, Sparkles, Volume2, Play, Pause, RotateCcw, CheckCircle2, AlertCircle } from 'lucide-react';
|
||||
import { Mic, MicOff, Sparkles, Volume2, CheckCircle2, ShieldCheck } from 'lucide-react';
|
||||
import { SAMPLE_AUDIO_PRESETS } from '@/lib/mock-data';
|
||||
|
||||
interface AmbientAudioRecorderProps {
|
||||
@@ -27,7 +27,6 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
|
||||
const [liveTranscript, setLiveTranscript] = useState('');
|
||||
const [showAppliedToast, setShowAppliedToast] = useState(false);
|
||||
|
||||
// Timer simulation
|
||||
useEffect(() => {
|
||||
let interval: any = null;
|
||||
if (isRecording) {
|
||||
@@ -44,8 +43,7 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
|
||||
if (!isRecording) {
|
||||
setIsRecording(true);
|
||||
setRecordingSeconds(0);
|
||||
setLiveTranscript('Listening to ambient doctor-patient dialogue in operatory...');
|
||||
// Simulate live ambient audio transcription
|
||||
setLiveTranscript('Hospital ambient listener active. Recording operatory encounter...');
|
||||
setTimeout(() => {
|
||||
setLiveTranscript(selectedPreset.audioTranscript);
|
||||
}, 2500);
|
||||
@@ -87,48 +85,48 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-br from-slate-900 via-slate-900 to-teal-950/40 border border-teal-500/30 rounded-2xl p-5 shadow-2xl text-slate-100">
|
||||
<div className="bg-white border border-slate-200 rounded-xl p-5 shadow-xs text-slate-800">
|
||||
{/* Top Banner */}
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-4 border-b border-slate-800">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-4 border-b border-slate-100">
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="p-1.5 rounded-lg bg-teal-500/20 text-teal-400 border border-teal-500/30">
|
||||
<span className="p-1.5 rounded-lg bg-sky-50 text-sky-700 border border-sky-100">
|
||||
<Sparkles className="w-4 h-4" />
|
||||
</span>
|
||||
<h3 className="font-semibold text-white text-base tracking-tight">
|
||||
Mediusa Ambient Clinical AI Scribe
|
||||
<h3 className="font-bold text-slate-900 text-base tracking-tight">
|
||||
Ambient Clinical Medical Scribe
|
||||
</h3>
|
||||
<span className="text-[11px] font-semibold px-2 py-0.5 rounded-full bg-indigo-500/20 text-indigo-300 border border-indigo-500/30">
|
||||
Powered by gpt-5.4-mini Clinical Engine
|
||||
<span className="text-[11px] font-bold px-2.5 py-0.5 rounded-full bg-sky-100 text-sky-800 border border-sky-200">
|
||||
Clinical Intelligence Engine (gpt-5.4-mini)
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-slate-400 mt-1">
|
||||
Zero typing required. Scribe listens to ambient doctor-patient encounter and converts conversational dialogue into compliant SOAP + CPT/ICD-10 codes.
|
||||
<p className="text-xs text-slate-500 mt-1">
|
||||
Hands-free documentation. Operatory audio automatically translates into compliant SOAP format and procedure codes.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Recording Status / Mic Button */}
|
||||
<div className="flex items-center gap-3">
|
||||
{isRecording && (
|
||||
<div className="flex items-center gap-2 text-xs font-mono font-semibold text-red-400 animate-pulse">
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-red-500" />
|
||||
LIVE {formatTime(recordingSeconds)}
|
||||
<div className="flex items-center gap-2 text-xs font-mono font-bold text-red-600 animate-pulse">
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-red-600" />
|
||||
RECORDING {formatTime(recordingSeconds)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={toggleRecording}
|
||||
className={`px-4 py-2 rounded-xl text-xs font-bold flex items-center gap-2 transition-all shadow-lg ${
|
||||
className={`px-4 py-2 rounded-lg text-xs font-bold flex items-center gap-2 transition shadow-xs ${
|
||||
isRecording
|
||||
? 'bg-red-500/20 text-red-400 border border-red-500/50 hover:bg-red-500/30'
|
||||
: 'bg-teal-500 hover:bg-teal-400 text-slate-950 shadow-teal-500/20'
|
||||
? 'bg-red-50 text-red-700 border border-red-200 hover:bg-red-100'
|
||||
: 'bg-sky-700 hover:bg-sky-800 text-white'
|
||||
}`}
|
||||
>
|
||||
{isRecording ? (
|
||||
<>
|
||||
<MicOff className="w-4 h-4" />
|
||||
Stop Listening
|
||||
Stop Recording
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -140,20 +138,21 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Waveform Graphic Animation */}
|
||||
<div className="mt-4 p-4 bg-slate-950/60 rounded-xl border border-slate-800/80">
|
||||
{/* Hospital Audio Monitor Waveform */}
|
||||
<div className="mt-4 p-4 bg-slate-900 rounded-lg border border-slate-800 text-slate-100">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-[11px] font-semibold text-slate-400 uppercase tracking-wider flex items-center gap-1.5">
|
||||
<Volume2 className="w-3.5 h-3.5 text-teal-400" />
|
||||
Operatory Ambient Stream
|
||||
<span className="text-xs font-bold text-slate-300 uppercase tracking-wider flex items-center gap-1.5">
|
||||
<Volume2 className="w-3.5 h-3.5 text-sky-400" />
|
||||
Medical Audio Feed
|
||||
</span>
|
||||
<span className="text-[10px] text-slate-500 font-mono">
|
||||
44.1kHz • 24-bit • HIPAA Speech Encryption
|
||||
<span className="text-[10px] text-slate-400 font-mono flex items-center gap-1">
|
||||
<ShieldCheck className="w-3 h-3 text-emerald-400" />
|
||||
HIPAA BAA End-to-End Encryption
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Dynamic Animated Bars */}
|
||||
<div className="h-10 flex items-center justify-center gap-1">
|
||||
<div className="h-9 flex items-center justify-center gap-1">
|
||||
{[
|
||||
12, 28, 45, 18, 62, 85, 40, 92, 70, 30, 80, 65, 45, 90, 35, 75, 55, 20, 68, 88,
|
||||
42, 78, 52, 22, 60, 95, 38, 72, 58, 25, 48, 82, 32, 64, 44, 15,
|
||||
@@ -162,11 +161,11 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
|
||||
key={i}
|
||||
className={`w-1 rounded-full transition-all duration-150 ${
|
||||
isRecording
|
||||
? 'bg-gradient-to-t from-teal-500 to-emerald-300 animate-pulse'
|
||||
: 'bg-slate-800'
|
||||
? 'bg-sky-400 animate-pulse'
|
||||
: 'bg-slate-700'
|
||||
}`}
|
||||
style={{
|
||||
height: isRecording ? `${Math.max(10, (height * (1 + (i % 3) * 0.2)) % 40)}px` : '6px',
|
||||
height: isRecording ? `${Math.max(8, (height * (1 + (i % 3) * 0.2)) % 36)}px` : '4px',
|
||||
animationDelay: `${(i * 40) % 600}ms`,
|
||||
}}
|
||||
/>
|
||||
@@ -178,8 +177,8 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
|
||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-4 mt-4">
|
||||
{/* Left 4 Cols: Presets */}
|
||||
<div className="md:col-span-4 flex flex-col gap-2">
|
||||
<label className="text-[11px] font-semibold text-slate-400 uppercase tracking-wider">
|
||||
Clinical Encounter Presets (1-Click Demo)
|
||||
<label className="text-xs font-bold text-slate-700 uppercase tracking-wider">
|
||||
Clinical Encounter Presets
|
||||
</label>
|
||||
<div className="space-y-2">
|
||||
{SAMPLE_AUDIO_PRESETS.map((preset) => (
|
||||
@@ -187,14 +186,14 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
|
||||
key={preset.id}
|
||||
type="button"
|
||||
onClick={() => handleSelectPreset(preset)}
|
||||
className={`w-full text-left p-2.5 rounded-xl border transition text-xs ${
|
||||
className={`w-full text-left p-3 rounded-lg border transition text-xs ${
|
||||
selectedPreset.id === preset.id
|
||||
? 'bg-slate-800 border-teal-500/60 text-white shadow-sm'
|
||||
: 'bg-slate-900/60 border-slate-800 text-slate-400 hover:bg-slate-800/40 hover:text-slate-200'
|
||||
? 'bg-sky-50/80 border-sky-300 text-sky-950 font-medium shadow-2xs'
|
||||
: 'bg-slate-50 border-slate-200 text-slate-600 hover:bg-slate-100 hover:text-slate-900'
|
||||
}`}
|
||||
>
|
||||
<div className="font-semibold text-slate-200 truncate">{preset.title}</div>
|
||||
<div className="text-[10px] text-teal-400 mt-0.5">Encounter Duration: {preset.duration}</div>
|
||||
<div className="font-bold text-slate-900 truncate">{preset.title}</div>
|
||||
<div className="text-[11px] text-sky-700 mt-0.5">Length: {preset.duration}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -203,50 +202,50 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
|
||||
type="button"
|
||||
onClick={handleSynthesizeSoap}
|
||||
disabled={isProcessingAI}
|
||||
className="mt-3 w-full py-2.5 px-4 rounded-xl text-xs font-bold bg-gradient-to-r from-teal-500 to-emerald-500 hover:from-teal-400 hover:to-emerald-400 text-slate-950 shadow-lg shadow-teal-500/20 transition flex items-center justify-center gap-2 disabled:opacity-50"
|
||||
className="mt-2 w-full py-2.5 px-4 rounded-lg text-xs font-bold bg-sky-700 hover:bg-sky-800 text-white shadow-xs transition flex items-center justify-center gap-2 disabled:opacity-50"
|
||||
>
|
||||
{isProcessingAI ? (
|
||||
<>
|
||||
<span className="w-3.5 h-3.5 border-2 border-slate-950 border-t-transparent rounded-full animate-spin" />
|
||||
AI Extracting SOAP...
|
||||
<span className="w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||
Structuring Medical Note...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Sparkles className="w-4 h-4 text-slate-950" />
|
||||
Extract SOAP & Auto-Codes
|
||||
<Sparkles className="w-4 h-4 text-white" />
|
||||
Synthesize Note & Auto-Codes
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Right 8 Cols: Dialogue Transcript */}
|
||||
<div className="md:col-span-8 bg-slate-950/70 border border-slate-800 rounded-xl p-3.5 flex flex-col justify-between">
|
||||
<div className="md:col-span-8 bg-slate-50 border border-slate-200 rounded-lg p-3.5 flex flex-col justify-between">
|
||||
<div>
|
||||
<div className="flex items-center justify-between pb-2 border-b border-slate-800 text-xs">
|
||||
<span className="font-semibold text-slate-300">Encounter Dialogue Feed</span>
|
||||
<span className="text-[10px] text-teal-400/90 font-mono">Live Whisper Stream</span>
|
||||
<div className="flex items-center justify-between pb-2 border-b border-slate-200 text-xs">
|
||||
<span className="font-bold text-slate-800">Transcript Log</span>
|
||||
<span className="text-[11px] text-slate-500 font-mono">Live Operatory Mic</span>
|
||||
</div>
|
||||
<p className="text-xs text-slate-300 whitespace-pre-line mt-2 font-mono leading-relaxed max-h-[160px] overflow-y-auto pr-1">
|
||||
<p className="text-xs text-slate-700 whitespace-pre-line mt-2 font-mono leading-relaxed max-h-[160px] overflow-y-auto pr-1">
|
||||
{liveTranscript || selectedPreset.audioTranscript}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 pt-2 border-t border-slate-800/80 flex items-center justify-between text-[11px] text-slate-400">
|
||||
<span className="flex items-center gap-1 text-teal-400">
|
||||
<CheckCircle2 className="w-3.5 h-3.5" />
|
||||
Auto-detects Subluxations, VAS score, CPT 98940, ICD-10 M99.0x
|
||||
<div className="mt-3 pt-2 border-t border-slate-200 flex items-center justify-between text-xs text-slate-500">
|
||||
<span className="flex items-center gap-1 text-sky-800 font-medium">
|
||||
<CheckCircle2 className="w-3.5 h-3.5 text-sky-700" />
|
||||
Auto-extracts SOAP, CPT 98940, ICD-10 M99.0x
|
||||
</span>
|
||||
<span className="text-slate-500">HIPAA BAA Compliant</span>
|
||||
<span className="text-slate-400">Speech-to-Text v2.4</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showAppliedToast && (
|
||||
<div className="mt-3 p-3 bg-emerald-500/20 border border-emerald-500/40 rounded-xl text-xs text-emerald-300 flex items-center justify-between animate-in fade-in slide-in-from-top-2 duration-200">
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle2 className="w-4 h-4 text-emerald-400" />
|
||||
<div className="mt-3 p-3 bg-emerald-50 border border-emerald-200 rounded-lg text-xs text-emerald-800 flex items-center justify-between animate-in fade-in duration-200">
|
||||
<div className="flex items-center gap-2 font-medium">
|
||||
<CheckCircle2 className="w-4 h-4 text-emerald-600" />
|
||||
<span>
|
||||
<strong>Success!</strong> Encounter conversation extracted into Subjective, Objective, Assessment, Plan, Spine segments, and Billing codes.
|
||||
<strong>Note Populated:</strong> Subjective, Objective, Assessment, Plan, Vertebrae listings, and Billing codes auto-synced.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user