feat: Doctor Onboarding Portal with statutory BAA execution and enclave deployment
This commit is contained in:
+108
-4
@@ -24,6 +24,7 @@ import {
|
||||
PrePaidPackage,
|
||||
WaitlistEntry,
|
||||
StaffRole,
|
||||
Provider,
|
||||
} from '@/types/clinical';
|
||||
import { CalendarView } from '@/components/calendar/CalendarView';
|
||||
import { SoapChartEditor } from '@/components/charting/SoapChartEditor';
|
||||
@@ -39,6 +40,7 @@ import { CourtAuditVaultModal } from '@/components/compliance/CourtAuditVaultMod
|
||||
import { CommandPalette } from '@/components/ui/CommandPalette';
|
||||
import { InactivityLockoutModal } from '@/components/ui/InactivityLockoutModal';
|
||||
import { ClinicalToastContainer, ToastMessage } from '@/components/ui/ClinicalToast';
|
||||
import { DoctorOnboardingView } from '@/components/onboarding/DoctorOnboardingView';
|
||||
import { clinicalAudio } from '@/lib/clinical-audio';
|
||||
import {
|
||||
Calendar,
|
||||
@@ -68,8 +70,8 @@ export default function Home() {
|
||||
const [tenants, setTenants] = useState<ClinicTenant[]>(INITIAL_TENANTS);
|
||||
const [activeTenantId, setActiveTenantId] = useState<string>(INITIAL_TENANTS[0].id);
|
||||
|
||||
// 'clinic' | 'patient' | 'superadmin'
|
||||
const [portalMode, setPortalMode] = useState<'clinic' | 'patient' | 'superadmin'>('clinic');
|
||||
// 'clinic' | 'patient' | 'superadmin' | 'onboarding'
|
||||
const [portalMode, setPortalMode] = useState<'clinic' | 'patient' | 'superadmin' | 'onboarding'>('clinic');
|
||||
|
||||
// Staff Role: 'doctor' | 'front_desk' | 'billing_admin'
|
||||
const [staffRole, setStaffRole] = useState<StaffRole>('doctor');
|
||||
@@ -81,6 +83,7 @@ export default function Home() {
|
||||
|
||||
const [appointments, setAppointments] = useState<Appointment[]>(INITIAL_APPOINTMENTS);
|
||||
const [patients, setPatients] = useState<Patient[]>(INITIAL_PATIENTS);
|
||||
const [providers, setProviders] = useState<Provider[]>(INITIAL_PROVIDERS);
|
||||
const [soapNotes, setSoapNotes] = useState<SoapNote[]>(INITIAL_SOAP_NOTES);
|
||||
const [superbills, setSuperbills] = useState<Superbill[]>(INITIAL_SUPERBILLS);
|
||||
const [products, setProducts] = useState<RetailProduct[]>(INITIAL_PRODUCTS);
|
||||
@@ -101,8 +104,8 @@ export default function Home() {
|
||||
const [activeSuperbill, setActiveSuperbill] = useState<Superbill>(INITIAL_SUPERBILLS[0]);
|
||||
|
||||
const activeTenant = tenants.find((t) => t.id === activeTenantId) || tenants[0];
|
||||
const activeProviders = INITIAL_PROVIDERS.filter((p) => p.tenantId === activeTenant.id);
|
||||
const activeProvider = activeProviders[0] || INITIAL_PROVIDERS[0];
|
||||
const activeProviders = providers.filter((p) => p.tenantId === activeTenant.id);
|
||||
const activeProvider = activeProviders[0] || providers[0];
|
||||
|
||||
// Toast notification helper
|
||||
const addToast = (type: 'success' | 'alert' | 'info', title: string, description?: string) => {
|
||||
@@ -261,6 +264,83 @@ export default function Home() {
|
||||
addToast('success', 'New Clinic Deployed', `${newTenant.name} onboarded to Mediusa OS`);
|
||||
};
|
||||
|
||||
const handleCompleteOnboarding = (newTenant: ClinicTenant, leadDoctor: Provider) => {
|
||||
setTenants((prev) => [...prev, newTenant]);
|
||||
setProviders((prev) => [...prev, leadDoctor]);
|
||||
setActiveTenantId(newTenant.id);
|
||||
|
||||
// Seed 1 active patient and encounter for instant clinic operation
|
||||
const samplePatientId = `pat-${Date.now()}`;
|
||||
const samplePatient: Patient = {
|
||||
id: samplePatientId,
|
||||
tenantId: newTenant.id,
|
||||
firstName: 'Michael',
|
||||
lastName: 'Sterling',
|
||||
email: 'm.sterling@example.com',
|
||||
phone: '(555) 349-1102',
|
||||
dob: '1984-06-12',
|
||||
gender: 'Male',
|
||||
address: '742 Evergreen Terrace, McLean, VA 22102',
|
||||
insuranceName: 'CareFirst BlueCross',
|
||||
insuranceId: 'CFB-94021-X',
|
||||
status: 'active',
|
||||
chiefComplaint: 'Acute thoracic and lumbar stiffness following marathon training; radiates to right hamstring',
|
||||
daysSinceLastVisit: 0,
|
||||
lastVisitDate: new Date().toISOString().substring(0, 10),
|
||||
nextAppointmentDate: new Date().toISOString().substring(0, 10),
|
||||
vitals: {
|
||||
bloodPressure: '122/78',
|
||||
heartRate: 68,
|
||||
temperature: '98.4°F',
|
||||
oxygenSat: 99,
|
||||
painLevel: 6,
|
||||
bmi: '23.4',
|
||||
allergies: ['Penicillin', 'Latex'],
|
||||
contraindications: ['High-velocity cervical rotation'],
|
||||
},
|
||||
carePlan: {
|
||||
title: 'Spinal Alignment & Thoracic Mobility Protocol',
|
||||
totalVisits: 12,
|
||||
completedVisits: 1,
|
||||
frequency: '2x / week for 6 weeks',
|
||||
targetCondition: 'Thoracolumbar Subluxation Complex',
|
||||
startDate: new Date().toISOString().substring(0, 10),
|
||||
status: 'on_track',
|
||||
},
|
||||
};
|
||||
|
||||
const sampleApt: Appointment = {
|
||||
id: `apt-${Date.now()}`,
|
||||
tenantId: newTenant.id,
|
||||
patientId: samplePatientId,
|
||||
patientName: `${samplePatient.firstName} ${samplePatient.lastName}`,
|
||||
patientPhone: samplePatient.phone,
|
||||
providerId: leadDoctor.id,
|
||||
providerName: leadDoctor.name,
|
||||
date: new Date().toISOString().substring(0, 10),
|
||||
time: '10:00 AM',
|
||||
durationMinutes: 45,
|
||||
serviceType: 'Initial Clinical Examination & Spinal Adjustment',
|
||||
status: 'confirmed',
|
||||
room: 'Operatory 1',
|
||||
notes: 'Initial evaluation under newly executed HIPAA BAA enclave. Full spinal visualizer and CMS-1500 queued.',
|
||||
fee: 85,
|
||||
};
|
||||
|
||||
setPatients((prev) => [samplePatient, ...prev]);
|
||||
setAppointments((prev) => [sampleApt, ...prev]);
|
||||
setActivePatient(samplePatient);
|
||||
|
||||
setPortalMode('clinic');
|
||||
setClinicTab('calendar');
|
||||
|
||||
addToast(
|
||||
'success',
|
||||
'Clinic Enclave Deployed & BAA Sealed',
|
||||
`${newTenant.name} is online on https://${newTenant.domain}. Lead Doctor: ${leadDoctor.name}.`
|
||||
);
|
||||
};
|
||||
|
||||
const handleSwitchTenant = (tenantId: string) => {
|
||||
clinicalAudio.playClick();
|
||||
setActiveTenantId(tenantId);
|
||||
@@ -496,6 +576,22 @@ export default function Home() {
|
||||
<Building2 className="w-3.5 h-3.5" />
|
||||
Mediusa Super-Admin
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
clinicalAudio.playClick();
|
||||
setPortalMode('onboarding');
|
||||
}}
|
||||
className={`px-3 py-1.5 rounded-md flex items-center gap-1.5 transition ${
|
||||
portalMode === 'onboarding'
|
||||
? 'bg-emerald-700 text-white font-bold shadow-xs'
|
||||
: 'text-emerald-700 hover:text-emerald-900 bg-emerald-50/70 hover:bg-emerald-100/70 border border-emerald-200/60'
|
||||
}`}
|
||||
>
|
||||
<Sparkles className="w-3.5 h-3.5 text-amber-500 animate-pulse" />
|
||||
+ Onboard Doctor (BAA)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -703,6 +799,13 @@ export default function Home() {
|
||||
onSwitchTenant={handleSwitchTenant}
|
||||
/>
|
||||
)}
|
||||
|
||||
{portalMode === 'onboarding' && (
|
||||
<DoctorOnboardingView
|
||||
onCompleteOnboarding={handleCompleteOnboarding}
|
||||
onCancel={() => setPortalMode('clinic')}
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
|
||||
{/* Cancellation Waitlist Modal */}
|
||||
@@ -754,6 +857,7 @@ export default function Home() {
|
||||
audioEnabled={audioEnabled}
|
||||
onOpenCourtVault={() => setIsCourtVaultOpen(true)}
|
||||
onLockTerminal={() => setIsTerminalLocked(true)}
|
||||
onOpenOnboarding={() => setPortalMode('onboarding')}
|
||||
/>
|
||||
|
||||
{/* Hospital Clinical Toast Notification System */}
|
||||
|
||||
Reference in New Issue
Block a user