feat: Select Procedures flow, batch-column NPI provider fix, auto PDF save
- Add 'Select Procedures' right-click option on appointment page (separate from Claims/PreAuth) - Select Procedures form saves CDT codes + NPI provider to AppointmentProcedure storage - Remove Save button from insurance claim form; Claims/PreAuth opens for insurance submission only - Claims/PreAuth auto-prefills from saved procedures including NPI provider - Batch-column: procedures npiProviderId takes priority over stale claim npiProviderId - Batch-column: auto-save PDF to patient Documents after successful submission (no socket needed) - Add npiProviderId column to AppointmentProcedure table (prisma db push) - Fix 'invalid db creation invocation': guard staffId, npiProviderId, procedureDate as Date object, totalBilled NaN guard - Add full error logging to batch-column catch block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -59,11 +59,14 @@ import {
|
||||
DirectComboButtons,
|
||||
RegularComboButtons,
|
||||
} from "@/components/procedure/procedure-combo-buttons";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
interface ClaimFormProps {
|
||||
patientId: number;
|
||||
appointmentId?: number;
|
||||
autoSubmit?: boolean;
|
||||
/** When true: form saves to AppointmentProcedure (Select Procedures flow), shows only Save button */
|
||||
proceduresOnly?: boolean;
|
||||
onSubmit: (data: ClaimFormData) => Promise<Claim>;
|
||||
onHandleAppointmentSubmit: (
|
||||
appointmentData: InsertAppointment | UpdateAppointment,
|
||||
@@ -78,6 +81,7 @@ export function ClaimForm({
|
||||
patientId,
|
||||
appointmentId,
|
||||
autoSubmit,
|
||||
proceduresOnly = false,
|
||||
onHandleAppointmentSubmit,
|
||||
onHandleUpdatePatient,
|
||||
onHandleForMHSeleniumClaim,
|
||||
@@ -90,8 +94,16 @@ export function ClaimForm({
|
||||
|
||||
const [prefillDone, setPrefillDone] = useState(false);
|
||||
const autoSubmittedRef = useRef(false);
|
||||
// When an existing claim is loaded for the appointment, store its ID so
|
||||
// the form submits an update instead of creating a new claim.
|
||||
const [existingClaimId, setExistingClaimId] = useState<number | null>(null);
|
||||
|
||||
const [directSubmitEnabled, setDirectSubmitEnabled] = useState(false);
|
||||
const [patient, setPatient] = useState<Patient | null>(null);
|
||||
// staffId from the appointment column — used for claim creation, not shown in UI
|
||||
const [appointmentStaffId, setAppointmentStaffId] = useState<number | null>(null);
|
||||
// npiProviderId loaded from AppointmentProcedure (2b) — restored to form when npiProviders load
|
||||
const [savedProcNpiId, setSavedProcNpiId] = useState<number | null>(null);
|
||||
|
||||
// Query patient based on given patient id
|
||||
const {
|
||||
@@ -211,6 +223,12 @@ export function ClaimForm({
|
||||
}
|
||||
|
||||
const appointment = await res.json();
|
||||
|
||||
// Capture the column staffId from the appointment
|
||||
if (!cancelled && appointment?.staffId) {
|
||||
setAppointmentStaffId(Number(appointment.staffId));
|
||||
}
|
||||
|
||||
// appointment.date is expected to be either "YYYY-MM-DD" or an ISO string.
|
||||
const rawDate = appointment?.date ?? appointment?.day ?? "";
|
||||
if (!rawDate) return;
|
||||
@@ -256,9 +274,104 @@ export function ClaimForm({
|
||||
|
||||
//
|
||||
|
||||
// 2. effect - prefill proceduresCodes (if exists for appointment) into serviceLines
|
||||
// 2a. Load existing saved claim for this appointment (if any).
|
||||
// Skipped in proceduresOnly mode — that mode always reads from AppointmentProcedure.
|
||||
useEffect(() => {
|
||||
if (!appointmentId) return;
|
||||
if (proceduresOnly) return;
|
||||
let cancelled = false;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const res = await apiRequest(
|
||||
"GET",
|
||||
`/api/claims/by-appointment/${appointmentId}`,
|
||||
);
|
||||
if (!res.ok) return; // 404 = no existing claim, that's fine
|
||||
|
||||
const claim = await res.json();
|
||||
if (cancelled || !claim?.id) return;
|
||||
|
||||
setExistingClaimId(claim.id);
|
||||
|
||||
// Restore service date
|
||||
const rawDate = claim.serviceDate ?? "";
|
||||
const claimDate = rawDate
|
||||
? String(rawDate).split("T")[0] ?? ""
|
||||
: "";
|
||||
if (claimDate) {
|
||||
try {
|
||||
setServiceDateValue(parseLocalDate(claimDate));
|
||||
setServiceDate(claimDate);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// Restore service lines
|
||||
const mappedLines = (claim.serviceLines ?? []).map((sl: any) => ({
|
||||
procedureCode: sl.procedureCode ?? "",
|
||||
procedureDate: sl.procedureDate
|
||||
? String(sl.procedureDate).split("T")[0]
|
||||
: claimDate,
|
||||
quad: sl.quad ?? "",
|
||||
arch: sl.arch ?? "",
|
||||
toothNumber: sl.toothNumber ?? "",
|
||||
toothSurface: sl.toothSurface ?? "",
|
||||
totalBilled: new Decimal(Number(sl.totalBilled ?? 0)),
|
||||
totalAdjusted: new Decimal(Number(sl.totalAdjusted ?? 0)),
|
||||
totalPaid: new Decimal(Number(sl.totalPaid ?? 0)),
|
||||
}));
|
||||
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
claimId: claim.id,
|
||||
serviceDate: claimDate || prev.serviceDate,
|
||||
serviceLines: mappedLines.length > 0 ? mappedLines : prev.serviceLines,
|
||||
remarks: claim.remarks ?? "",
|
||||
missingTeethStatus: (claim.missingTeethStatus as MissingTeethStatus) ?? "No_missing",
|
||||
missingTeeth: (claim.missingTeeth as Record<string, "X" | "O">) ?? {},
|
||||
insuranceProvider: claim.insuranceProvider ?? "",
|
||||
...(claim.staffId ? { staffId: claim.staffId } : {}),
|
||||
claimFiles: claim.claimFiles ?? [],
|
||||
}));
|
||||
|
||||
// Restore staff selection
|
||||
if (claim.staffId && staffMembersRaw.length > 0) {
|
||||
const matchedStaff = staffMembersRaw.find(
|
||||
(s) => Number(s.id) === Number(claim.staffId),
|
||||
);
|
||||
if (matchedStaff) setStaff(matchedStaff);
|
||||
}
|
||||
|
||||
// Restore NPI provider selection
|
||||
if ((claim as any).npiProviderId && npiProviders.length > 0) {
|
||||
const matchedNpi = npiProviders.find(
|
||||
(p) => Number(p.id) === Number((claim as any).npiProviderId),
|
||||
);
|
||||
if (matchedNpi) {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
npiProvider: {
|
||||
npiNumber: matchedNpi.npiNumber,
|
||||
providerName: matchedNpi.providerName,
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
setPrefillDone(true);
|
||||
} catch (err) {
|
||||
// no existing claim — silently continue
|
||||
}
|
||||
})();
|
||||
|
||||
return () => { cancelled = true; };
|
||||
}, [appointmentId]);
|
||||
|
||||
// 2b. Prefill procedures from AppointmentProcedure records.
|
||||
// Skipped when an existing claim was already loaded above.
|
||||
useEffect(() => {
|
||||
if (!appointmentId) return;
|
||||
if (existingClaimId) return; // existing claim takes priority
|
||||
|
||||
let cancelled = false;
|
||||
|
||||
@@ -291,6 +404,20 @@ export function ClaimForm({
|
||||
serviceLines: mappedLines,
|
||||
}));
|
||||
|
||||
// Restore NPI provider from saved procedures
|
||||
if (data.npiProviderId) {
|
||||
const npiId = Number(data.npiProviderId);
|
||||
setSavedProcNpiId(npiId);
|
||||
// Apply immediately if providers are already loaded
|
||||
const matched = npiProviders.find((p) => p.id === npiId);
|
||||
if (matched) {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
npiProvider: { npiNumber: matched.npiNumber, providerName: matched.providerName },
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
setPrefillDone(true);
|
||||
} catch (err) {
|
||||
console.error("Failed to prefill procedures:", err);
|
||||
@@ -300,7 +427,20 @@ export function ClaimForm({
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [appointmentId, serviceDate]);
|
||||
}, [appointmentId, serviceDate, existingClaimId]);
|
||||
|
||||
// Restore NPI provider from saved procedures when npiProviders list loads after 2b
|
||||
useEffect(() => {
|
||||
if (!savedProcNpiId || !npiProviders.length) return;
|
||||
if (form.npiProvider?.npiNumber) return; // already set
|
||||
const matched = npiProviders.find((p) => p.id === savedProcNpiId);
|
||||
if (matched) {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
npiProvider: { npiNumber: matched.npiNumber, providerName: matched.providerName },
|
||||
}));
|
||||
}
|
||||
}, [savedProcNpiId, npiProviders]);
|
||||
|
||||
// Update service date when calendar date changes
|
||||
const onServiceDateChange = (date: Date | undefined) => {
|
||||
@@ -421,7 +561,7 @@ export function ClaimForm({
|
||||
patientId: patientId || 0,
|
||||
appointmentId: 0,
|
||||
userId: Number(user?.id),
|
||||
staffId: Number(staff?.id),
|
||||
staffId: appointmentStaffId ?? Number(staff?.id),
|
||||
patientName: `${patient?.firstName} ${patient?.lastName}`.trim(),
|
||||
memberId: patient?.insuranceId ?? "",
|
||||
dateOfBirth: normalizeToIsoDateString(patient?.dateOfBirth),
|
||||
@@ -602,7 +742,7 @@ export function ClaimForm({
|
||||
const appointmentData = {
|
||||
patientId: patientId,
|
||||
date: serviceDate,
|
||||
staffId: staff?.id,
|
||||
staffId: appointmentStaffId ?? staff?.id,
|
||||
};
|
||||
const created = await onHandleAppointmentSubmit(appointmentData);
|
||||
|
||||
@@ -648,7 +788,7 @@ export function ClaimForm({
|
||||
const createdClaim = await onSubmit({
|
||||
...formToCreateClaim,
|
||||
serviceLines: filteredServiceLines,
|
||||
staffId: Number(staff?.id),
|
||||
staffId: appointmentStaffId ?? Number(staff?.id),
|
||||
patientId: patientId,
|
||||
insuranceProvider: "MassHealth",
|
||||
appointmentId: appointmentIdToUse!,
|
||||
@@ -660,7 +800,7 @@ export function ClaimForm({
|
||||
...f,
|
||||
dateOfBirth: toMMDDYYYY(f.dateOfBirth),
|
||||
serviceLines: filteredServiceLines,
|
||||
staffId: Number(staff?.id),
|
||||
staffId: appointmentStaffId ?? Number(staff?.id),
|
||||
npiProvider: f.npiProvider,
|
||||
patientId: patientId,
|
||||
insuranceProvider: "Mass Health",
|
||||
@@ -741,7 +881,7 @@ export function ClaimForm({
|
||||
...f,
|
||||
dateOfBirth: toMMDDYYYY(f.dateOfBirth),
|
||||
serviceLines: filteredServiceLines,
|
||||
staffId: Number(staff?.id),
|
||||
staffId: appointmentStaffId ?? Number(staff?.id),
|
||||
npiProvider: f.npiProvider,
|
||||
patientId: patientId,
|
||||
insuranceProvider: "Mass Health",
|
||||
@@ -791,7 +931,7 @@ export function ClaimForm({
|
||||
const appointmentData = {
|
||||
patientId: patientId,
|
||||
date: serviceDate,
|
||||
staffId: staff?.id,
|
||||
staffId: appointmentStaffId ?? staff?.id,
|
||||
};
|
||||
const created = await onHandleAppointmentSubmit(appointmentData);
|
||||
|
||||
@@ -821,7 +961,7 @@ export function ClaimForm({
|
||||
|
||||
// 3. Create Claim(if not)
|
||||
// Filter out empty service lines (empty procedureCode)
|
||||
const { uploadedFiles, insuranceSiteKey, ...formToCreateClaim } = form;
|
||||
const { uploadedFiles, insuranceSiteKey, npiProvider: _npi, ...formToCreateClaim } = form;
|
||||
|
||||
// build claimFiles metadata from uploadedFiles (only filename + mimeType)
|
||||
const claimFilesMeta: ClaimFileMeta[] = (uploadedFiles || []).map((f) => ({
|
||||
@@ -832,7 +972,7 @@ export function ClaimForm({
|
||||
const createdClaim = await onSubmit({
|
||||
...formToCreateClaim,
|
||||
serviceLines: filteredServiceLines,
|
||||
staffId: Number(staff?.id),
|
||||
staffId: appointmentStaffId ?? Number(staff?.id),
|
||||
patientId: patientId,
|
||||
insuranceProvider: "MassHealth",
|
||||
appointmentId: appointmentIdToUse!,
|
||||
@@ -843,6 +983,137 @@ export function ClaimForm({
|
||||
onClose();
|
||||
};
|
||||
|
||||
const uploadAttachmentsToLocalFolder = async (files: File[]): Promise<ClaimFileMeta[]> => {
|
||||
if (!files.length) return [];
|
||||
|
||||
const patientName = patient?.firstName && patient?.lastName
|
||||
? `${patient.firstName} ${patient.lastName}`
|
||||
: patient?.firstName ?? `patient-${patientId}`;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("patientName", patientName);
|
||||
files.forEach((f) => formData.append("files", f));
|
||||
|
||||
const res = await apiRequest("POST", "/api/claims/upload-attachments", formData);
|
||||
const data = await res.json();
|
||||
return (data.data ?? []) as ClaimFileMeta[];
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
const filteredServiceLines = form.serviceLines.filter(
|
||||
(line) => (line.procedureCode ?? "").trim() !== "",
|
||||
);
|
||||
|
||||
if (filteredServiceLines.length === 0) {
|
||||
toast({
|
||||
title: "No procedure codes",
|
||||
description: "Please add at least one procedure code before saving.",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const missingFields: string[] = [];
|
||||
if (!form.memberId?.trim()) missingFields.push("Member ID");
|
||||
if (!form.dateOfBirth?.trim()) missingFields.push("Date of Birth");
|
||||
if (missingFields.length > 0) {
|
||||
toast({
|
||||
title: "Missing Required Fields",
|
||||
description: `Please fill out: ${missingFields.join(", ")}`,
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let appointmentIdToUse = appointmentId;
|
||||
|
||||
if (appointmentIdToUse == null) {
|
||||
const appointmentData = {
|
||||
patientId: patientId,
|
||||
date: serviceDate,
|
||||
staffId: appointmentStaffId ?? staff?.id,
|
||||
};
|
||||
const created = await onHandleAppointmentSubmit(appointmentData);
|
||||
if (typeof created === "number" && created > 0) {
|
||||
appointmentIdToUse = created;
|
||||
} else if (created && typeof (created as any).id === "number") {
|
||||
appointmentIdToUse = (created as any).id;
|
||||
}
|
||||
}
|
||||
|
||||
const { uploadedFiles, insuranceSiteKey, npiProvider, ...formToSave } = form;
|
||||
|
||||
const claimFilesMeta: ClaimFileMeta[] = uploadedFiles?.length
|
||||
? await uploadAttachmentsToLocalFolder(uploadedFiles)
|
||||
: [];
|
||||
|
||||
// Find the npiProviderId matching the currently selected NPI provider
|
||||
const selectedNpiProviderId = npiProvider?.npiNumber
|
||||
? npiProviders.find((p) => p.npiNumber === npiProvider.npiNumber)?.id ?? null
|
||||
: null;
|
||||
|
||||
try {
|
||||
await onSubmit({
|
||||
...formToSave,
|
||||
serviceLines: filteredServiceLines,
|
||||
staffId: appointmentStaffId ?? Number(staff?.id),
|
||||
patientId: patientId,
|
||||
insuranceProvider: "MassHealth",
|
||||
appointmentId: appointmentIdToUse!,
|
||||
claimFiles: claimFilesMeta,
|
||||
...(selectedNpiProviderId ? { npiProviderId: selectedNpiProviderId } : {}),
|
||||
isDraft: true,
|
||||
});
|
||||
toast({ title: "Saved", description: "Claim saved successfully." });
|
||||
} catch (err: any) {
|
||||
toast({
|
||||
title: "Save failed",
|
||||
description: err?.message ?? "Failed to save claim.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Saves CDT codes + NPI provider to AppointmentProcedure (proceduresOnly mode)
|
||||
const handleProceduresSave = async () => {
|
||||
if (!appointmentId || !patientId) {
|
||||
toast({ title: "Missing appointment", description: "Cannot save without an appointment.", variant: "destructive" });
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredServiceLines = form.serviceLines.filter(
|
||||
(line) => (line.procedureCode ?? "").trim() !== "",
|
||||
);
|
||||
if (filteredServiceLines.length === 0) {
|
||||
toast({ title: "No procedure codes", description: "Please add at least one procedure code.", variant: "destructive" });
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedNpiProviderId = form.npiProvider?.npiNumber
|
||||
? (npiProviders.find((p) => p.npiNumber === form.npiProvider!.npiNumber)?.id ?? null)
|
||||
: null;
|
||||
|
||||
try {
|
||||
const res = await apiRequest("POST", "/api/appointment-procedures/save-for-appointment", {
|
||||
appointmentId,
|
||||
patientId,
|
||||
npiProviderId: selectedNpiProviderId,
|
||||
procedures: filteredServiceLines.map((l) => ({
|
||||
procedureCode: l.procedureCode,
|
||||
fee: Number(l.totalBilled) || null,
|
||||
toothNumber: l.toothNumber || null,
|
||||
toothSurface: l.toothSurface || null,
|
||||
})),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) throw new Error("Failed to save procedures");
|
||||
toast({ title: "Procedures saved", description: `${data.count} procedure(s) saved.` });
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
toast({ title: "Save failed", description: err?.message ?? "Failed to save procedures.", variant: "destructive" });
|
||||
}
|
||||
};
|
||||
|
||||
// for direct combo button.
|
||||
const applyComboAndThenMH = async (
|
||||
comboId: keyof typeof PROCEDURE_COMBOS,
|
||||
@@ -1020,47 +1291,6 @@ export function ClaimForm({
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
{/* Treating doctor */}
|
||||
<Label className="flex items-center ml-2">
|
||||
Treating Doctor
|
||||
</Label>
|
||||
<Select
|
||||
value={staff?.id?.toString() || ""}
|
||||
onValueChange={(id) => {
|
||||
const selected = staffMembersRaw.find(
|
||||
(member) => member.id?.toString() === id,
|
||||
);
|
||||
if (selected) {
|
||||
setStaff(selected);
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
staffId: Number(selected.id),
|
||||
}));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-36">
|
||||
<SelectValue
|
||||
placeholder={staff ? staff.name : "Select Staff"}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
|
||||
<SelectContent>
|
||||
{staffMembersRaw.map((member) => {
|
||||
if (member.id === undefined) return null;
|
||||
|
||||
return (
|
||||
<SelectItem
|
||||
key={member.id}
|
||||
value={member.id.toString()}
|
||||
>
|
||||
{member.name}
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
{/* Rendering Npi Provider */}
|
||||
<Label className="flex items-center ml-2">
|
||||
Rendering Provider
|
||||
@@ -1108,10 +1338,33 @@ export function ClaimForm({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Switch
|
||||
id="direct-submit-toggle"
|
||||
checked={directSubmitEnabled}
|
||||
onCheckedChange={setDirectSubmitEnabled}
|
||||
/>
|
||||
<Label htmlFor="direct-submit-toggle" className="text-sm cursor-pointer select-none">
|
||||
Direct Submission {directSubmitEnabled ? <span className="text-green-600 font-semibold">ON</span> : <span className="text-muted-foreground">OFF</span>}
|
||||
</Label>
|
||||
</div>
|
||||
<DirectComboButtons
|
||||
onDirectCombo={(comboKey) =>
|
||||
applyComboAndThenMH(comboKey as any)
|
||||
}
|
||||
onDirectCombo={(comboKey) => {
|
||||
if (directSubmitEnabled) {
|
||||
applyComboAndThenMH(comboKey as any);
|
||||
} else {
|
||||
setForm((prev) => {
|
||||
const next = applyComboToForm(
|
||||
prev,
|
||||
comboKey as any,
|
||||
patient?.dateOfBirth ?? "",
|
||||
{ replaceAll: false, lineDate: prev.serviceDate },
|
||||
);
|
||||
setTimeout(() => scrollToLine(0), 0);
|
||||
return next;
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1464,37 +1717,51 @@ export function ClaimForm({
|
||||
{/* Insurance Carriers */}
|
||||
<div className="pt-6">
|
||||
<h3 className="text-xl font-semibold mb-4 text-center">
|
||||
Insurance Carriers
|
||||
{proceduresOnly ? "Save Procedures" : "Insurance Carriers"}
|
||||
</h3>
|
||||
<div className="flex justify-between">
|
||||
<Button
|
||||
className="w-32"
|
||||
variant="secondary"
|
||||
onClick={() => handleMHSubmit()}
|
||||
>
|
||||
MH
|
||||
</Button>
|
||||
<Button
|
||||
className="w-32"
|
||||
variant="secondary"
|
||||
onClick={() => handleMHPreAuth()}
|
||||
>
|
||||
MH PreAuth
|
||||
</Button>
|
||||
<Button
|
||||
className="w-32"
|
||||
variant="secondary"
|
||||
onClick={handleAddService}
|
||||
>
|
||||
Add Service
|
||||
</Button>
|
||||
<Button className="w-32" variant="outline">
|
||||
Delta MA
|
||||
</Button>
|
||||
<Button className="w-32" variant="outline">
|
||||
Others
|
||||
</Button>
|
||||
</div>
|
||||
{proceduresOnly ? (
|
||||
/* ── Select Procedures mode: Save only ── */
|
||||
<div className="flex justify-center">
|
||||
<Button
|
||||
className="w-48"
|
||||
variant="default"
|
||||
onClick={handleProceduresSave}
|
||||
>
|
||||
Save Procedures
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
/* ── Insurance Claim mode: submit buttons, no Save ── */
|
||||
<div className="flex justify-between">
|
||||
<Button
|
||||
className="w-32"
|
||||
variant="secondary"
|
||||
onClick={() => handleMHSubmit()}
|
||||
>
|
||||
MH
|
||||
</Button>
|
||||
<Button
|
||||
className="w-32"
|
||||
variant="secondary"
|
||||
onClick={() => handleMHPreAuth()}
|
||||
>
|
||||
MH PreAuth
|
||||
</Button>
|
||||
<Button
|
||||
className="w-32"
|
||||
variant="secondary"
|
||||
onClick={handleAddService}
|
||||
>
|
||||
Add Service
|
||||
</Button>
|
||||
<Button className="w-32" variant="outline">
|
||||
Delta MA
|
||||
</Button>
|
||||
<Button className="w-32" variant="outline">
|
||||
Others
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user