feat: polish UX +5% with Cmd+K Command Palette, Web Audio tactile feedback, Patient Clinical Vitals HUD, Fast Macros & Toasts

This commit is contained in:
2026-09-05 15:44:58 -07:00
parent dd5057d4e3
commit bfe527fb33
9 changed files with 1191 additions and 21 deletions
+155 -5
View File
@@ -35,6 +35,9 @@ import { RetailInventoryView } from '@/components/pos/RetailInventoryView';
import { MembershipsView } from '@/components/memberships/MembershipsView';
import { TelehealthRoom } from '@/components/telehealth/TelehealthRoom';
import { WaitlistModal } from '@/components/waitlist/WaitlistModal';
import { CommandPalette } from '@/components/ui/CommandPalette';
import { ClinicalToastContainer, ToastMessage } from '@/components/ui/ClinicalToast';
import { clinicalAudio } from '@/lib/clinical-audio';
import {
Calendar,
FileText,
@@ -51,6 +54,10 @@ import {
Shield,
ShieldAlert,
UserCheck,
Search,
Volume2,
VolumeX,
Sparkles,
} from 'lucide-react';
export default function Home() {
@@ -78,6 +85,11 @@ export default function Home() {
const [waitlist, setWaitlist] = useState<WaitlistEntry[]>(INITIAL_WAITLIST);
const [isWaitlistOpen, setIsWaitlistOpen] = useState(false);
// Polish state: Command Palette, Toasts & Audio
const [isCommandPaletteOpen, setIsCommandPaletteOpen] = useState(false);
const [toasts, setToasts] = useState<ToastMessage[]>([]);
const [audioEnabled, setAudioEnabled] = useState(true);
const [activePatient, setActivePatient] = useState<Patient>(INITIAL_PATIENTS[0]);
const [activeSoapNote, setActiveSoapNote] = useState<SoapNote | undefined>(INITIAL_SOAP_NOTES[0]);
const [activeSuperbill, setActiveSuperbill] = useState<Superbill>(INITIAL_SUPERBILLS[0]);
@@ -86,7 +98,52 @@ export default function Home() {
const activeProviders = INITIAL_PROVIDERS.filter((p) => p.tenantId === activeTenant.id);
const activeProvider = activeProviders[0] || INITIAL_PROVIDERS[0];
// Toast notification helper
const addToast = (type: 'success' | 'alert' | 'info', title: string, description?: string) => {
const id = `toast-${Date.now()}-${Math.random().toString(36).substring(2, 6)}`;
const newToast: ToastMessage = {
id,
type,
title,
description,
timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }),
};
setToasts((prev) => [...prev, newToast]);
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 4500);
};
const handleDismissToast = (id: string) => {
setToasts((prev) => prev.filter((t) => t.id !== id));
};
// Keyboard shortcut listener for Cmd+K / Ctrl+K
React.useEffect(() => {
const handleGlobalKeyDown = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
setIsCommandPaletteOpen((prev) => !prev);
}
};
window.addEventListener('keydown', handleGlobalKeyDown);
return () => window.removeEventListener('keydown', handleGlobalKeyDown);
}, []);
const handleToggleAudio = () => {
const next = !audioEnabled;
setAudioEnabled(next);
clinicalAudio.setEnabled(next);
if (next) {
clinicalAudio.playSuccess();
addToast('info', 'Tactile Audio Active', 'Synthesized Web Audio clicks & chimes enabled');
} else {
addToast('info', 'Tactile Audio Muted', 'Sound effects silenced');
}
};
const handleSelectAppointment = (apt: Appointment) => {
clinicalAudio.playClick();
const patientMatch = patients.find((p) => p.id === apt.patientId) || patients[0];
setActivePatient(patientMatch);
@@ -101,12 +158,15 @@ export default function Home() {
};
const handleUpdateAppointmentStatus = (aptId: string, status: Appointment['status']) => {
clinicalAudio.playClick();
setAppointments((prev) =>
prev.map((a) => (a.id === aptId ? { ...a, status } : a))
);
addToast('info', 'Encounter Status Updated', `Appointment transitioned to ${status}`);
};
const handleSaveSoapNote = (note: SoapNote) => {
clinicalAudio.playSuccess();
setSoapNotes((prev) => {
const idx = prev.findIndex((s) => s.id === note.id);
if (idx >= 0) {
@@ -117,9 +177,11 @@ export default function Home() {
return [...prev, note];
});
setActiveSoapNote(note);
addToast('success', 'Chart Synced to HIPAA Vault', `${note.patientName}${note.status === 'signed' ? 'Signed & Locked' : 'Draft Saved'}`);
};
const handleGenerateSuperbillFromNote = (note: SoapNote) => {
clinicalAudio.playSuccess();
const newSb: Superbill = {
id: `sb-${Date.now()}`,
tenantId: activeTenant.id,
@@ -153,9 +215,11 @@ export default function Home() {
setSuperbills((prev) => [newSb, ...prev]);
setActiveSuperbill(newSb);
setClinicTab('billing');
addToast('success', 'Superbill Claim Created', `${newSb.invoiceNumber}$${newSb.totalAmount.toFixed(2)} Fee Schedule`);
};
const handleMarkPaid = (superbillId: string, method: Superbill['paymentMethod']) => {
clinicalAudio.playSuccess();
setSuperbills((prev) =>
prev.map((sb) =>
sb.id === superbillId
@@ -171,9 +235,11 @@ export default function Home() {
paymentMethod: method,
}));
}
addToast('success', 'Stripe Payment Captured', `Receipt processed via ${method}`);
};
const handlePatientBookingComplete = (newAptData: any) => {
clinicalAudio.playSuccess();
const newApt: Appointment = {
id: `apt-${Date.now()}`,
tenantId: activeTenant.id,
@@ -181,34 +247,44 @@ export default function Home() {
...newAptData,
};
setAppointments((prev) => [newApt, ...prev]);
addToast('success', 'Intake & Booking Confirmed', `${newApt.patientName} scheduled for ${newApt.time}`);
};
const handleAddTenant = (newTenant: ClinicTenant) => {
setTenants((prev) => [...prev, newTenant]);
addToast('success', 'New Clinic Deployed', `${newTenant.name} onboarded to Mediusa OS`);
};
const handleSwitchTenant = (tenantId: string) => {
clinicalAudio.playClick();
setActiveTenantId(tenantId);
setPortalMode('clinic');
setClinicTab('calendar');
};
const handleUpdateProductStock = (productId: string, newStock: number) => {
clinicalAudio.playClick();
setProducts((prev) =>
prev.map((p) => (p.id === productId ? { ...p, stockQty: newStock } : p))
);
addToast('info', 'POS Inventory Updated', `Stock quantity adjusted to ${newStock}`);
};
const handleEnrollPatientInMembership = (patientId: string, planName: string) => {
clinicalAudio.playSuccess();
setPatients((prev) =>
prev.map((p) => (p.id === patientId ? { ...p, activeMembership: planName } : p))
);
addToast('success', 'Membership Enrolled', `Patient subscribed to ${planName}`);
};
const handleAutoFillWaitlistPatient = (entryId: string) => {
clinicalAudio.playPing();
const entry = waitlist.find((w) => w.id === entryId);
setWaitlist((prev) =>
prev.map((w) => (w.id === entryId ? { ...w, status: 'notified' } : w))
);
addToast('alert', 'Waitlist SMS Dispatched', `Slot opening sent to ${entry?.patientName || 'patient'}`);
};
return (
@@ -226,7 +302,7 @@ export default function Home() {
<div className="text-xs font-black tracking-tight text-slate-900 flex items-center gap-1.5">
<span>MEDIUSA CLINIC OS</span>
<span className="text-[10px] px-2 py-0.5 rounded-full bg-sky-100 text-sky-800 font-bold border border-sky-200">
CLINICAL v2.4
CLINICAL v2.5
</span>
</div>
<div className="text-xs text-slate-500 font-mono flex items-center gap-1 mt-0.5">
@@ -236,6 +312,36 @@ export default function Home() {
</div>
</div>
{/* Quick Command Palette Trigger (Cmd+K) */}
<button
type="button"
onClick={() => {
clinicalAudio.playClick();
setIsCommandPaletteOpen(true);
}}
className="hidden xl:flex items-center gap-2 px-3 py-1.5 bg-slate-50 hover:bg-slate-100 border border-slate-200 rounded-lg text-slate-500 text-xs transition shadow-2xs"
>
<Search className="w-3.5 h-3.5 text-slate-400" />
<span>Search patients or actions...</span>
<kbd className="px-1.5 py-0.5 text-[9px] font-mono bg-white border border-slate-200 rounded text-slate-500 font-bold">
K
</kbd>
</button>
{/* Audio Toggle Button */}
<button
type="button"
onClick={handleToggleAudio}
title={audioEnabled ? 'Tactile Audio Active (Click to Mute)' : 'Tactile Audio Muted (Click to Enable)'}
className={`p-1.5 rounded-lg border text-xs transition flex items-center gap-1 shadow-2xs ${
audioEnabled
? 'bg-sky-50 border-sky-200 text-sky-700 hover:bg-sky-100'
: 'bg-slate-100 border-slate-200 text-slate-400 hover:bg-slate-200'
}`}
>
{audioEnabled ? <Volume2 className="w-4 h-4" /> : <VolumeX className="w-4 h-4" />}
</button>
{/* Clinic Dropdown */}
<div className="relative">
<select
@@ -257,7 +363,11 @@ export default function Home() {
<span className="text-[10px] uppercase font-bold text-slate-500 px-1.5">Role:</span>
<button
type="button"
onClick={() => setStaffRole('doctor')}
onClick={() => {
clinicalAudio.playClick();
setStaffRole('doctor');
addToast('info', 'Role: Attending Doctor (D.C.)', 'Full clinical SOAP, 2D spine & telehealth unlocked');
}}
className={`px-2 py-1 rounded text-xs font-bold transition ${
staffRole === 'doctor'
? 'bg-white text-sky-800 shadow-2xs border border-slate-200'
@@ -270,10 +380,12 @@ export default function Home() {
<button
type="button"
onClick={() => {
clinicalAudio.playClick();
setStaffRole('front_desk');
if (clinicTab === 'charting' || clinicTab === 'telehealth') {
setClinicTab('calendar');
}
addToast('alert', 'Role: Front Desk (HIPAA Safe)', 'Protected medical notes locked for privacy');
}}
className={`px-2 py-1 rounded text-xs font-bold transition ${
staffRole === 'front_desk'
@@ -286,7 +398,11 @@ export default function Home() {
</button>
<button
type="button"
onClick={() => setStaffRole('billing_admin')}
onClick={() => {
clinicalAudio.playClick();
setStaffRole('billing_admin');
addToast('info', 'Role: Billing Administrator', 'Superbill claims and memberships prioritized');
}}
className={`px-2 py-1 rounded text-xs font-bold transition ${
staffRole === 'billing_admin'
? 'bg-white text-emerald-800 shadow-2xs border border-slate-200'
@@ -303,7 +419,10 @@ export default function Home() {
<div className="flex items-center gap-1 bg-slate-100 p-1 rounded-lg border border-slate-200 text-xs font-semibold">
<button
type="button"
onClick={() => setPortalMode('clinic')}
onClick={() => {
clinicalAudio.playClick();
setPortalMode('clinic');
}}
className={`px-3 py-1.5 rounded-md flex items-center gap-1.5 transition ${
portalMode === 'clinic'
? 'bg-sky-700 text-white font-bold shadow-xs'
@@ -316,7 +435,10 @@ export default function Home() {
<button
type="button"
onClick={() => setPortalMode('patient')}
onClick={() => {
clinicalAudio.playClick();
setPortalMode('patient');
}}
className={`px-3 py-1.5 rounded-md flex items-center gap-1.5 transition ${
portalMode === 'patient'
? 'bg-sky-700 text-white font-bold shadow-xs'
@@ -555,6 +677,34 @@ export default function Home() {
onAutoFillPatient={handleAutoFillWaitlistPatient}
/>
{/* Global Command Palette (Cmd+K) */}
<CommandPalette
isOpen={isCommandPaletteOpen}
onClose={() => setIsCommandPaletteOpen(false)}
patients={patients}
onSelectPatient={(p) => {
setActivePatient(p);
const existing = soapNotes.find((s) => s.patientId === p.id);
setActiveSoapNote(existing);
}}
onNavigateTab={(tab) => setClinicTab(tab)}
onOpenWaitlist={() => setIsWaitlistOpen(true)}
onSetStaffRole={(role) => {
setStaffRole(role);
if (role === 'front_desk' && (clinicTab === 'charting' || clinicTab === 'telehealth')) {
setClinicTab('calendar');
}
}}
onToggleAudio={handleToggleAudio}
audioEnabled={audioEnabled}
/>
{/* Hospital Clinical Toast Notification System */}
<ClinicalToastContainer
toasts={toasts}
onDismiss={handleDismissToast}
/>
{/* Hospital Footer */}
<footer className="bg-white border-t border-slate-200 py-4 px-6 text-center text-xs text-slate-500">
<div className="flex flex-col sm:flex-row items-center justify-between max-w-7xl mx-auto gap-2">