feat(frontend): wire Vite app to FastAPI parser with NDJSON streaming + Upload page
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
import type { Activity, Claim, Provider, Remittance } from "@/types";
|
||||
|
||||
export const sampleProviders: Provider[] = [
|
||||
{
|
||||
npi: "1730187395",
|
||||
name: "Cedar Park Family Medicine",
|
||||
taxId: "47-3829104",
|
||||
address: "1401 Medical Pkwy",
|
||||
city: "Cedar Park",
|
||||
state: "TX",
|
||||
zip: "78613",
|
||||
phone: "(512) 555-0142",
|
||||
claimCount: 1284,
|
||||
outstandingAr: 184320,
|
||||
},
|
||||
{
|
||||
npi: "1528471902",
|
||||
name: "Lakeside Orthopedics",
|
||||
taxId: "83-1172654",
|
||||
address: "900 W Lake Dr",
|
||||
city: "Austin",
|
||||
state: "TX",
|
||||
zip: "78746",
|
||||
phone: "(512) 555-0188",
|
||||
claimCount: 742,
|
||||
outstandingAr: 221540,
|
||||
},
|
||||
{
|
||||
npi: "1982036471",
|
||||
name: "Hill Country Pediatrics",
|
||||
taxId: "74-5520183",
|
||||
address: "205 State Hwy 27",
|
||||
city: "Marble Falls",
|
||||
state: "TX",
|
||||
zip: "78654",
|
||||
phone: "(830) 555-0117",
|
||||
claimCount: 956,
|
||||
outstandingAr: 96210,
|
||||
},
|
||||
];
|
||||
|
||||
const payers = [
|
||||
"Blue Cross Blue Shield",
|
||||
"United Healthcare",
|
||||
"Aetna",
|
||||
"Cigna",
|
||||
"Humana",
|
||||
"Medicare",
|
||||
"Medicaid TX",
|
||||
];
|
||||
|
||||
const cpts = ["99213", "99214", "99203", "93000", "85025", "80053", "73721", "20610"];
|
||||
|
||||
const firstNames = [
|
||||
"Avery",
|
||||
"Jordan",
|
||||
"Riley",
|
||||
"Casey",
|
||||
"Morgan",
|
||||
"Quinn",
|
||||
"Reese",
|
||||
"Sasha",
|
||||
"Drew",
|
||||
"Hayden",
|
||||
];
|
||||
const lastNames = [
|
||||
"Nguyen",
|
||||
"Patel",
|
||||
"Garcia",
|
||||
"Cohen",
|
||||
"Okafor",
|
||||
"Martinez",
|
||||
"Hwang",
|
||||
"Brooks",
|
||||
"Singh",
|
||||
"Tanaka",
|
||||
];
|
||||
|
||||
function rand<T>(arr: T[]): T {
|
||||
return arr[Math.floor(Math.random() * arr.length)]!;
|
||||
}
|
||||
function daysAgo(n: number): string {
|
||||
const d = new Date();
|
||||
d.setDate(d.getDate() - n);
|
||||
return d.toISOString();
|
||||
}
|
||||
|
||||
function buildClaims(): Claim[] {
|
||||
const claims: Claim[] = [];
|
||||
for (let i = 0; i < 96; i++) {
|
||||
const provider = rand(sampleProviders);
|
||||
const status = rand<Claim["status"]>([
|
||||
"submitted",
|
||||
"accepted",
|
||||
"denied",
|
||||
"paid",
|
||||
"paid",
|
||||
"paid",
|
||||
"pending",
|
||||
]);
|
||||
const billed = 80 + Math.floor(Math.random() * 1400);
|
||||
const received =
|
||||
status === "paid" ? Math.floor(billed * (0.6 + Math.random() * 0.4))
|
||||
: status === "denied" ? 0
|
||||
: 0;
|
||||
claims.push({
|
||||
id: `CLM-${(10428 + i).toString()}`,
|
||||
patientName: `${rand(firstNames)} ${rand(lastNames)}`,
|
||||
providerNpi: provider.npi,
|
||||
payerName: rand(payers),
|
||||
cptCode: rand(cpts),
|
||||
billedAmount: billed,
|
||||
receivedAmount: received,
|
||||
status,
|
||||
submissionDate: daysAgo(Math.floor(Math.random() * 200)),
|
||||
denialReason:
|
||||
status === "denied" ?
|
||||
rand([
|
||||
"CO-97: Service included in another service",
|
||||
"CO-16: Claim lacks information",
|
||||
"CO-50: Non-covered service",
|
||||
"PR-1: Deductible amount",
|
||||
])
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
return claims.sort(
|
||||
(a, b) => new Date(b.submissionDate).getTime() - new Date(a.submissionDate).getTime()
|
||||
);
|
||||
}
|
||||
|
||||
function buildRemittances(claims: Claim[]): Remittance[] {
|
||||
const paid = claims.filter((c) => c.status === "paid");
|
||||
return paid.slice(0, 24).map((c, i) => ({
|
||||
id: `REM-${(7782 + i).toString()}`,
|
||||
claimId: c.id,
|
||||
payerName: c.payerName,
|
||||
paidAmount: c.receivedAmount,
|
||||
adjustmentAmount: Math.max(0, c.billedAmount - c.receivedAmount - 5),
|
||||
receivedDate: c.submissionDate,
|
||||
checkNumber: `EFT-${100000 + Math.floor(Math.random() * 899999)}`,
|
||||
status: rand<Remittance["status"]>(["received", "posted", "reconciled"]),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildActivity(claims: Claim[]): Activity[] {
|
||||
const events: Activity[] = claims.slice(0, 28).map((c) => {
|
||||
const kind: Activity["kind"] =
|
||||
c.status === "paid" ? "claim_paid" :
|
||||
c.status === "denied" ? "claim_denied" :
|
||||
c.status === "accepted" ? "claim_accepted" :
|
||||
"claim_submitted";
|
||||
return {
|
||||
id: `ACT-${c.id}`,
|
||||
kind,
|
||||
message:
|
||||
kind === "claim_paid" ?
|
||||
`Paid ${c.id} · ${c.patientName}` :
|
||||
kind === "claim_denied" ?
|
||||
`Denied ${c.id} · ${c.patientName}` :
|
||||
kind === "claim_accepted" ?
|
||||
`Accepted ${c.id} · ${c.patientName}` :
|
||||
`Submitted ${c.id} · ${c.patientName}`,
|
||||
timestamp: c.submissionDate,
|
||||
npi: c.providerNpi,
|
||||
amount: c.billedAmount,
|
||||
};
|
||||
});
|
||||
return events.sort(
|
||||
(a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
|
||||
);
|
||||
}
|
||||
|
||||
const claims = buildClaims();
|
||||
|
||||
export const sampleClaims: Claim[] = claims;
|
||||
export const sampleRemittances: Remittance[] = buildRemittances(claims);
|
||||
export const sampleActivity: Activity[] = buildActivity(claims);
|
||||
Reference in New Issue
Block a user