560 lines
23 KiB
TypeScript
560 lines
23 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState } from 'react';
|
|
import {
|
|
SoapNote,
|
|
Patient,
|
|
Provider,
|
|
SpinalAdjustmentEntry,
|
|
CptCodeItem,
|
|
Icd10CodeItem,
|
|
ClinicalDiscipline,
|
|
} from '@/types/clinical';
|
|
import { SpineVisualizer } from '@/components/ui/SpineVisualizer';
|
|
import { AmbientAudioRecorder } from '@/components/ui/AmbientAudioRecorder';
|
|
import { PatientClinicalHud } from '@/components/ui/PatientClinicalHud';
|
|
import { clinicalAudio } from '@/lib/clinical-audio';
|
|
import { STANDARD_CPT_CODES, STANDARD_ICD10_CODES, DISCIPLINE_PRESETS } from '@/lib/mock-data';
|
|
import {
|
|
CheckCircle,
|
|
Copy,
|
|
DollarSign,
|
|
ChevronLeft,
|
|
Tag,
|
|
ShieldCheck,
|
|
Video,
|
|
Layers,
|
|
Lock,
|
|
} from 'lucide-react';
|
|
|
|
interface SoapChartEditorProps {
|
|
patient: Patient;
|
|
provider: Provider;
|
|
initialSoapNote?: SoapNote;
|
|
onSaveSoapNote: (note: SoapNote) => void;
|
|
onGenerateSuperbill: (note: SoapNote) => void;
|
|
onLaunchTelehealth: () => void;
|
|
onBackToCalendar: () => void;
|
|
}
|
|
|
|
export const SoapChartEditor: React.FC<SoapChartEditorProps> = ({
|
|
patient,
|
|
provider,
|
|
initialSoapNote,
|
|
onSaveSoapNote,
|
|
onGenerateSuperbill,
|
|
onLaunchTelehealth,
|
|
onBackToCalendar,
|
|
}) => {
|
|
const [discipline, setDiscipline] = useState<ClinicalDiscipline>(
|
|
initialSoapNote?.discipline || 'chiropractic'
|
|
);
|
|
|
|
const [subjective, setSubjective] = useState(
|
|
initialSoapNote?.subjective ||
|
|
`Patient presents for scheduled visit ${patient.carePlan.completedVisits + 1} of ${
|
|
patient.carePlan.totalVisits
|
|
}. Chief complaint: ${patient.chiefComplaint}. VAS pain reported at 4/10.`
|
|
);
|
|
const [objective, setObjective] = useState(
|
|
initialSoapNote?.objective ||
|
|
'Postural examination reveals mild anterior head carriage and unleveling of right iliac crest. Motion palpation identifies segmental hypomobility with paraspinal guarding.'
|
|
);
|
|
const [assessment, setAssessment] = useState(
|
|
initialSoapNote?.assessment ||
|
|
'Segmental and somatic dysfunction of lumbar and cervical spine. Patient progressing steadily toward functional goals outlined in care plan.'
|
|
);
|
|
const [plan, setPlan] = useState(
|
|
initialSoapNote?.plan ||
|
|
'1. High velocity low amplitude (HVLA) manipulative therapy delivered to listed subluxations.\n2. Prescribed postural home stabilization exercises.\n3. Return in 3 days for scheduled care plan visit.'
|
|
);
|
|
const [adjustments, setAdjustments] = useState<SpinalAdjustmentEntry[]>(
|
|
initialSoapNote?.spinalAdjustments || [
|
|
{ vertebra: 'L4', region: 'Lumbar', listing: 'Right Posterior (RP)', technique: 'Diversified' },
|
|
{ vertebra: 'Sacrum', region: 'Pelvis/Sacrum', listing: 'Right Sacral Base Anterior', technique: 'Thompson Drop' },
|
|
]
|
|
);
|
|
const [selectedIcd10, setSelectedIcd10] = useState<Icd10CodeItem[]>(
|
|
initialSoapNote?.icd10Codes || [STANDARD_ICD10_CODES[2], STANDARD_ICD10_CODES[5]]
|
|
);
|
|
const [selectedCpt, setSelectedCpt] = useState<CptCodeItem[]>(
|
|
initialSoapNote?.cptCodes || [STANDARD_CPT_CODES[0], STANDARD_CPT_CODES[3]]
|
|
);
|
|
const [vasScore, setVasScore] = useState<number>(initialSoapNote?.vasScore || 3);
|
|
const [isSigned, setIsSigned] = useState<boolean>(initialSoapNote?.status === 'signed');
|
|
const [signedTimestamp, setSignedTimestamp] = useState<string | undefined>(initialSoapNote?.signedAt);
|
|
|
|
const handleApplyExtractedSoap = (data: {
|
|
vasScore: number;
|
|
subjective: string;
|
|
objective: string;
|
|
assessment: string;
|
|
plan: string;
|
|
spinalAdjustments: SpinalAdjustmentEntry[];
|
|
icd10: string[];
|
|
cpt: string[];
|
|
}) => {
|
|
setVasScore(data.vasScore);
|
|
setSubjective(data.subjective);
|
|
setObjective(data.objective);
|
|
setAssessment(data.assessment);
|
|
setPlan(data.plan);
|
|
|
|
if (data.spinalAdjustments && data.spinalAdjustments.length > 0) {
|
|
setAdjustments(data.spinalAdjustments);
|
|
}
|
|
|
|
const matchedIcds = STANDARD_ICD10_CODES.filter((icd) => data.icd10.includes(icd.code));
|
|
if (matchedIcds.length > 0) setSelectedIcd10(matchedIcds);
|
|
|
|
const matchedCpts = STANDARD_CPT_CODES.filter((cpt) => data.cpt.includes(cpt.code));
|
|
if (matchedCpts.length > 0) setSelectedCpt(matchedCpts);
|
|
};
|
|
|
|
const handleSwitchDiscipline = (newDiscipline: ClinicalDiscipline) => {
|
|
clinicalAudio.playClick();
|
|
setDiscipline(newDiscipline);
|
|
const preset = DISCIPLINE_PRESETS[newDiscipline];
|
|
if (preset) {
|
|
setSubjective(preset.sampleSubjective);
|
|
setObjective(preset.sampleObjective);
|
|
setAssessment(preset.sampleAssessment);
|
|
setPlan(preset.samplePlan);
|
|
|
|
const matchedIcds = STANDARD_ICD10_CODES.filter((icd) => preset.icd10Codes.includes(icd.code));
|
|
if (matchedIcds.length > 0) setSelectedIcd10(matchedIcds);
|
|
|
|
const matchedCpts = STANDARD_CPT_CODES.filter((cpt) => preset.cptCodes.includes(cpt.code));
|
|
if (matchedCpts.length > 0) setSelectedCpt(matchedCpts);
|
|
}
|
|
};
|
|
|
|
const handleToggleAdjustment = (entry: SpinalAdjustmentEntry) => {
|
|
clinicalAudio.playClick();
|
|
setAdjustments((prev) => {
|
|
const exists = prev.some((a) => a.vertebra === entry.vertebra);
|
|
if (exists) {
|
|
return prev.filter((a) => a.vertebra !== entry.vertebra);
|
|
} else {
|
|
return [...prev, entry];
|
|
}
|
|
});
|
|
};
|
|
|
|
const handleCloneLastNote = () => {
|
|
clinicalAudio.playClick();
|
|
setSubjective('Patient reports continued symptom improvement following last spinal adjustment. Morning stiffness resolved within 10 minutes. Current pain rated 3/10.');
|
|
setObjective('Palpation reveals decreased tone in lumbar paraspinals. Persistent fixation noted at L4-L5 with right sacral torsion.');
|
|
setAssessment('Care plan compliance high. Significant restoration of active range of motion noted.');
|
|
setPlan('1. Diversified adjustment delivered to indicated segments.\n2. Manual myofascial release 10 minutes.\n3. Continue active home rehabilitation.');
|
|
};
|
|
|
|
const handleSignChart = () => {
|
|
clinicalAudio.playSuccess();
|
|
const now = new Date().toISOString();
|
|
setIsSigned(true);
|
|
setSignedTimestamp(now);
|
|
|
|
const savedNote: SoapNote = {
|
|
id: initialSoapNote?.id || `soap-${Date.now()}`,
|
|
tenantId: patient.tenantId,
|
|
patientId: patient.id,
|
|
patientName: `${patient.firstName} ${patient.lastName}`,
|
|
providerId: provider.id,
|
|
providerName: provider.name,
|
|
date: '2026-09-05',
|
|
status: 'signed',
|
|
discipline,
|
|
vasScore,
|
|
subjective,
|
|
objective,
|
|
assessment,
|
|
plan,
|
|
spinalAdjustments: adjustments,
|
|
icd10Codes: selectedIcd10,
|
|
cptCodes: selectedCpt,
|
|
signedAt: now,
|
|
signedBy: `${provider.name}, ${provider.credentials} (NPI ${provider.npi})`,
|
|
};
|
|
|
|
onSaveSoapNote(savedNote);
|
|
};
|
|
|
|
const handleCreateSuperbillClick = () => {
|
|
clinicalAudio.playSuccess();
|
|
const savedNote: SoapNote = {
|
|
id: initialSoapNote?.id || `soap-${Date.now()}`,
|
|
tenantId: patient.tenantId,
|
|
patientId: patient.id,
|
|
patientName: `${patient.firstName} ${patient.lastName}`,
|
|
providerId: provider.id,
|
|
providerName: provider.name,
|
|
date: '2026-09-05',
|
|
status: isSigned ? 'signed' : 'draft',
|
|
discipline,
|
|
vasScore,
|
|
subjective,
|
|
objective,
|
|
assessment,
|
|
plan,
|
|
spinalAdjustments: adjustments,
|
|
icd10Codes: selectedIcd10,
|
|
cptCodes: selectedCpt,
|
|
signedAt: signedTimestamp,
|
|
signedBy: isSigned ? `${provider.name}, ${provider.credentials}` : undefined,
|
|
};
|
|
|
|
onSaveSoapNote(savedNote);
|
|
onGenerateSuperbill(savedNote);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* Patient Clinical HUD Ribbon */}
|
|
<PatientClinicalHud patient={patient} />
|
|
|
|
{/* Top Patient Header Bar */}
|
|
<div className="bg-white border border-slate-200 rounded-xl p-5 shadow-xs flex flex-col md:flex-row md:items-center justify-between gap-4">
|
|
<div className="flex items-center gap-3">
|
|
<button
|
|
type="button"
|
|
onClick={onBackToCalendar}
|
|
className="p-2 bg-slate-100 hover:bg-slate-200 text-slate-700 rounded-lg transition"
|
|
title="Back to Calendar"
|
|
>
|
|
<ChevronLeft className="w-5 h-5" />
|
|
</button>
|
|
|
|
<div>
|
|
<div className="flex items-center gap-2">
|
|
<h3 className="text-lg font-bold text-slate-900">
|
|
{patient.firstName} {patient.lastName}
|
|
</h3>
|
|
<div className="flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-emerald-50 border border-emerald-200 text-emerald-800 text-[10px] font-semibold">
|
|
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
|
|
<span>HIPAA Vault Sync</span>
|
|
</div>
|
|
{isSigned ? (
|
|
<span className="text-xs px-2.5 py-0.5 rounded-full bg-emerald-50 text-emerald-700 border border-emerald-200 font-semibold flex items-center gap-1">
|
|
<ShieldCheck className="w-3.5 h-3.5" /> Signed & Locked
|
|
</span>
|
|
) : (
|
|
<span className="text-xs px-2.5 py-0.5 rounded-full bg-amber-50 text-amber-700 border border-amber-200 font-semibold">
|
|
In Progress (Draft)
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex flex-wrap items-center gap-3 text-xs text-slate-500 mt-1">
|
|
<span>DOB: {patient.dob}</span>
|
|
<span>•</span>
|
|
<span>Insurance: {patient.insuranceName}</span>
|
|
<span>•</span>
|
|
<span className="text-sky-800 font-medium">Attending: {provider.name}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Action buttons */}
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<button
|
|
type="button"
|
|
onClick={onLaunchTelehealth}
|
|
className="px-3.5 py-2 rounded-lg bg-sky-100 hover:bg-sky-200 text-sky-900 text-xs font-bold flex items-center gap-1.5 transition border border-sky-200"
|
|
>
|
|
<Video className="w-3.5 h-3.5 text-sky-700" />
|
|
Launch Telehealth
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={handleCloneLastNote}
|
|
className="px-3 py-2 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 border border-slate-200 text-xs font-semibold flex items-center gap-1.5 transition"
|
|
>
|
|
<Copy className="w-3.5 h-3.5 text-slate-600" />
|
|
Clone Last Note
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={handleSignChart}
|
|
disabled={isSigned}
|
|
className={`px-4 py-2 rounded-lg text-xs font-bold flex items-center gap-1.5 transition shadow-xs ${
|
|
isSigned
|
|
? 'bg-emerald-50 text-emerald-700 border border-emerald-200 cursor-default'
|
|
: 'bg-emerald-700 hover:bg-emerald-800 text-white'
|
|
}`}
|
|
>
|
|
<CheckCircle className="w-4 h-4" />
|
|
{isSigned ? 'Signed & Locked' : 'Sign & Complete Note'}
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={handleCreateSuperbillClick}
|
|
className="px-4 py-2 rounded-lg bg-sky-700 hover:bg-sky-800 text-white text-xs font-bold flex items-center gap-1.5 shadow-xs transition"
|
|
>
|
|
<DollarSign className="w-4 h-4" />
|
|
Generate Superbill
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Multi-Discipline Template Presets Bar */}
|
|
<div className="bg-white border border-slate-200 rounded-xl p-3 shadow-xs flex flex-col sm:flex-row sm:items-center justify-between gap-3 text-xs">
|
|
<div className="flex items-center gap-2 font-bold text-slate-700">
|
|
<Layers className="w-4 h-4 text-sky-700" />
|
|
<span>Clinical Discipline Template:</span>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1 bg-slate-100 p-1 rounded-lg border border-slate-200">
|
|
{[
|
|
{ id: 'chiropractic', label: '🦴 Chiropractic (Spine CMT)' },
|
|
{ id: 'physical_therapy', label: '🏃 Physical Therapy & Rehab' },
|
|
{ id: 'acupuncture', label: '🪡 Acupuncture Meridian' },
|
|
{ id: 'massage_therapy', label: '💆 Medical Massage' },
|
|
].map((d) => (
|
|
<button
|
|
key={d.id}
|
|
type="button"
|
|
onClick={() => handleSwitchDiscipline(d.id as ClinicalDiscipline)}
|
|
className={`px-3 py-1.5 rounded-md font-semibold transition whitespace-nowrap ${
|
|
discipline === d.id
|
|
? 'bg-white text-sky-800 shadow-xs border border-slate-200/80'
|
|
: 'text-slate-600 hover:text-slate-900'
|
|
}`}
|
|
>
|
|
{d.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Ambient AI Scribe */}
|
|
<AmbientAudioRecorder onApplyExtractedSoap={handleApplyExtractedSoap} />
|
|
|
|
{/* Spine Subluxation Visualizer (shown prominently for chiropractic & physical therapy) */}
|
|
<SpineVisualizer
|
|
adjustments={adjustments}
|
|
onToggleAdjustment={handleToggleAdjustment}
|
|
readOnly={isSigned}
|
|
/>
|
|
|
|
{/* Structured SOAP Fields */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
|
{/* S */}
|
|
<div className="bg-white border border-slate-200 rounded-xl p-4 shadow-xs flex flex-col justify-between">
|
|
<div>
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-100 mb-2">
|
|
<span className="text-xs font-bold text-sky-800 uppercase tracking-wider flex items-center gap-1.5">
|
|
<span className="w-5 h-5 rounded bg-sky-100 text-sky-800 flex items-center justify-center font-bold">
|
|
S
|
|
</span>
|
|
Subjective History & Complaint
|
|
</span>
|
|
<span className="text-xs font-mono font-semibold text-slate-600 bg-slate-100 px-2 py-0.5 rounded">
|
|
VAS: {vasScore}/10
|
|
</span>
|
|
</div>
|
|
<textarea
|
|
rows={4}
|
|
value={subjective}
|
|
disabled={isSigned}
|
|
onChange={(e) => setSubjective(e.target.value)}
|
|
className="w-full bg-slate-50 border border-slate-200 rounded-lg p-3 text-xs text-slate-800 focus:bg-white focus:outline-none focus:border-sky-500 resize-none"
|
|
/>
|
|
</div>
|
|
<div className="text-[11px] text-slate-400 mt-2">
|
|
Auto-populated from Intake and Ambient Scribe.
|
|
</div>
|
|
</div>
|
|
|
|
{/* O */}
|
|
<div className="bg-white border border-slate-200 rounded-xl p-4 shadow-xs flex flex-col justify-between">
|
|
<div>
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-100 mb-2">
|
|
<span className="text-xs font-bold text-sky-800 uppercase tracking-wider flex items-center gap-1.5">
|
|
<span className="w-5 h-5 rounded bg-sky-100 text-sky-800 flex items-center justify-center font-bold">
|
|
O
|
|
</span>
|
|
Objective Exam & Palpation
|
|
</span>
|
|
<span className="text-xs font-mono font-semibold text-slate-600 bg-slate-100 px-2 py-0.5 rounded">
|
|
{adjustments.length} Segment(s)
|
|
</span>
|
|
</div>
|
|
<textarea
|
|
rows={4}
|
|
value={objective}
|
|
disabled={isSigned}
|
|
onChange={(e) => setObjective(e.target.value)}
|
|
className="w-full bg-slate-50 border border-slate-200 rounded-lg p-3 text-xs text-slate-800 focus:bg-white focus:outline-none focus:border-sky-500 resize-none"
|
|
/>
|
|
</div>
|
|
<div className="text-[11px] text-slate-400 mt-2">
|
|
Vertebrae selected in Spine Map sync automatically.
|
|
</div>
|
|
</div>
|
|
|
|
{/* A */}
|
|
<div className="bg-white border border-slate-200 rounded-xl p-4 shadow-xs flex flex-col justify-between">
|
|
<div>
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-100 mb-2">
|
|
<span className="text-xs font-bold text-sky-800 uppercase tracking-wider flex items-center gap-1.5">
|
|
<span className="w-5 h-5 rounded bg-sky-100 text-sky-800 flex items-center justify-center font-bold">
|
|
A
|
|
</span>
|
|
Clinical Assessment & Progress
|
|
</span>
|
|
</div>
|
|
<textarea
|
|
rows={4}
|
|
value={assessment}
|
|
disabled={isSigned}
|
|
onChange={(e) => setAssessment(e.target.value)}
|
|
className="w-full bg-slate-50 border border-slate-200 rounded-lg p-3 text-xs text-slate-800 focus:bg-white focus:outline-none focus:border-sky-500 resize-none"
|
|
/>
|
|
</div>
|
|
<div className="text-[11px] text-slate-400 mt-2">
|
|
Mapped to ICD-10 diagnostic codes below.
|
|
</div>
|
|
</div>
|
|
|
|
{/* P */}
|
|
<div className="bg-white border border-slate-200 rounded-xl p-4 shadow-xs flex flex-col justify-between">
|
|
<div>
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-100 mb-2">
|
|
<span className="text-xs font-bold text-sky-800 uppercase tracking-wider flex items-center gap-1.5">
|
|
<span className="w-5 h-5 rounded bg-sky-100 text-sky-800 flex items-center justify-center font-bold">
|
|
P
|
|
</span>
|
|
Treatment Plan & Modalities
|
|
</span>
|
|
</div>
|
|
<textarea
|
|
rows={4}
|
|
value={plan}
|
|
disabled={isSigned}
|
|
onChange={(e) => setPlan(e.target.value)}
|
|
className="w-full bg-slate-50 border border-slate-200 rounded-lg p-3 text-xs text-slate-800 focus:bg-white focus:outline-none focus:border-sky-500 resize-none"
|
|
/>
|
|
</div>
|
|
<div className="text-[11px] text-slate-400 mt-2">
|
|
Populates CPT procedure line items on Superbill.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* ICD-10 & CPT Selectors */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
|
{/* ICD-10 */}
|
|
<div className="bg-white border border-slate-200 rounded-xl p-4 shadow-xs">
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-100 mb-3">
|
|
<span className="text-xs font-bold text-slate-800 uppercase tracking-wider flex items-center gap-1.5">
|
|
<Tag className="w-3.5 h-3.5 text-sky-700" />
|
|
ICD-10 Diagnostic Codes
|
|
</span>
|
|
<span className="text-xs text-sky-800 font-mono font-bold">
|
|
{selectedIcd10.length} Selected
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-wrap gap-1.5 max-h-40 overflow-y-auto pr-1">
|
|
{STANDARD_ICD10_CODES.map((item) => {
|
|
const active = selectedIcd10.some((c) => c.code === item.code);
|
|
return (
|
|
<button
|
|
key={item.code}
|
|
type="button"
|
|
disabled={isSigned}
|
|
onClick={() => {
|
|
if (active) {
|
|
setSelectedIcd10((prev) => prev.filter((c) => c.code !== item.code));
|
|
} else {
|
|
setSelectedIcd10((prev) => [...prev, item]);
|
|
}
|
|
}}
|
|
className={`px-3 py-1.5 rounded-md text-xs font-medium text-left transition ${
|
|
active
|
|
? 'bg-sky-700 text-white font-bold shadow-xs'
|
|
: 'bg-slate-100 text-slate-700 hover:bg-slate-200'
|
|
}`}
|
|
>
|
|
<span className="font-mono font-bold mr-1">{item.code}</span>
|
|
<span className="text-[11px] opacity-90 truncate">{item.description}</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* CPT Codes */}
|
|
<div className="bg-white border border-slate-200 rounded-xl p-4 shadow-xs">
|
|
<div className="flex items-center justify-between pb-2 border-b border-slate-100 mb-3">
|
|
<span className="text-xs font-bold text-slate-800 uppercase tracking-wider flex items-center gap-1.5">
|
|
<DollarSign className="w-3.5 h-3.5 text-emerald-600" />
|
|
CPT Procedure Codes
|
|
</span>
|
|
<span className="text-xs text-emerald-800 font-mono font-bold">
|
|
Fee Total: ${selectedCpt.reduce((sum, c) => sum + c.fee, 0)}
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-wrap gap-1.5 max-h-40 overflow-y-auto pr-1">
|
|
{STANDARD_CPT_CODES.map((item) => {
|
|
const active = selectedCpt.some((c) => c.code === item.code);
|
|
return (
|
|
<button
|
|
key={item.code}
|
|
type="button"
|
|
disabled={isSigned}
|
|
onClick={() => {
|
|
if (active) {
|
|
setSelectedCpt((prev) => prev.filter((c) => c.code !== item.code));
|
|
} else {
|
|
setSelectedCpt((prev) => [...prev, item]);
|
|
}
|
|
}}
|
|
className={`px-3 py-1.5 rounded-md text-xs font-medium text-left transition flex items-center justify-between gap-2 ${
|
|
active
|
|
? 'bg-emerald-700 text-white font-bold shadow-xs'
|
|
: 'bg-slate-100 text-slate-700 hover:bg-slate-200'
|
|
}`}
|
|
>
|
|
<div>
|
|
<span className="font-mono font-bold mr-1">{item.code}</span>
|
|
<span className="text-[11px] opacity-90 truncate">{item.description}</span>
|
|
</div>
|
|
<span className="font-mono text-emerald-800 bg-white/20 px-1.5 rounded shrink-0 font-bold">
|
|
${item.fee}
|
|
</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Signature Attestation Footer */}
|
|
{isSigned && (
|
|
<div className="p-4 bg-emerald-50 border border-emerald-200 rounded-xl flex items-center justify-between text-xs text-emerald-900">
|
|
<div className="flex items-center gap-2">
|
|
<ShieldCheck className="w-5 h-5 text-emerald-600" />
|
|
<div>
|
|
<strong>Electronically Signed by:</strong> {provider.name}, {provider.credentials} (NPI {provider.npi})
|
|
<div className="text-[11px] text-emerald-700 mt-0.5">
|
|
Timestamp: {signedTimestamp || '2026-09-05T09:25:00-07:00'} • Immutable Legal Record
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button
|
|
type="button"
|
|
onClick={handleCreateSuperbillClick}
|
|
className="px-3.5 py-1.5 bg-emerald-700 hover:bg-emerald-800 text-white font-bold rounded-lg transition"
|
|
>
|
|
Open Superbill
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|