fix: allow letters in insurance ID; add patient state (default MA)

- Backend insurance ID check now accepts letters + digits (BCBS IDs have
  a letter prefix), matching the frontend schema; create route validates
  the normalized body
- Patient.state column (default "MA") with State select on the patient
  form; ADA claim form uses the patient's state instead of the office's
- Rebuild stale packages/db compiled .js so the runtime schemas include
  new fields (state, office billing NPI fields, Telnyx settings)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 23:29:27 -04:00
co-authored by Claude Opus 5.5
parent 2c0c595af5
commit 1abc2c705d
664 changed files with 6263 additions and 843 deletions
+1 -4
View File
@@ -239,10 +239,7 @@ router.post("/", async (req: Request, res: Response): Promise<any> => {
});
}
// Validate request body
const patientData = insertPatientSchema.parse({
...req.body,
userId: req.user!.id,
});
const patientData = insertPatientSchema.parse(body);
// Check for duplicate insuranceId if it's provided
if (patientData.insuranceId) {
+6 -1
View File
@@ -56,6 +56,7 @@ export type AdaClaimInput = {
gender?: string | null;
address?: string | null;
city?: string | null;
state?: string | null;
zipCode?: string | null;
insuranceId?: string | null;
groupNumber?: string | null;
@@ -209,7 +210,11 @@ async function fillOnePage(
// 12-23. Subscriber / patient
const patientName = `${patient.lastName}, ${patient.firstName}`;
const patientCsz = cityStateZip(patient.city, patient.address || patient.city ? officeState : "", patient.zipCode);
const patientCsz = cityStateZip(
patient.city,
patient.state || (patient.address || patient.city ? officeState : ""),
patient.zipCode,
);
const dob = fmtDate(patient.dateOfBirth);
const gender = genderCode(patient.gender);
const genderBox = { M: "Check Box1", F: "Check Box2", U: "Check Box3" }[gender];
+4 -4
View File
@@ -9,7 +9,7 @@ export function normalizeInsuranceId(raw: unknown): string | undefined {
s = raw;
} else {
// Not acceptable type
throw new Error("Insurance ID must be a numeric string.");
throw new Error("Insurance ID must be a string.");
}
// Remove all whitespace
@@ -18,9 +18,9 @@ export function normalizeInsuranceId(raw: unknown): string | undefined {
// If empty after cleaning, treat as undefined
if (cleaned === "") return undefined;
// Only digits allowed (since you said it's numeric)
if (!/^\d+$/.test(cleaned)) {
throw new Error("Insurance ID must contain only digits.");
// Letters and digits allowed (e.g. BCBS IDs carry a letter prefix)
if (!/^[A-Za-z0-9]+$/.test(cleaned)) {
throw new Error("Insurance ID must contain only letters and digits.");
}
return cleaned;
@@ -33,6 +33,15 @@ import {
import { z } from "zod";
import { DateInputField } from "@/components/ui/dateInputField";
// New England first (most patients), then the remaining states alphabetically
const US_STATES = [
"MA", "NH", "RI", "CT", "VT", "ME",
"AK", "AL", "AR", "AZ", "CA", "CO", "DC", "DE", "FL", "GA", "HI", "IA",
"ID", "IL", "IN", "KS", "KY", "LA", "MD", "MI", "MN", "MO", "MS", "MT",
"NC", "ND", "NE", "NJ", "NM", "NV", "NY", "OH", "OK", "OR", "PA", "SC",
"SD", "TN", "TX", "UT", "VA", "WA", "WI", "WV", "WY",
];
interface PatientFormProps {
patient?: Patient;
extractedInfo?: {
@@ -102,6 +111,7 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
email: "",
address: "",
city: "",
state: "MA",
zipCode: "",
insuranceProvider: "",
insuranceId: extractedInfo?.insuranceId || "",
@@ -366,6 +376,34 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
)}
/>
<FormField
control={form.control}
name="state"
render={({ field }) => (
<FormItem>
<FormLabel>State</FormLabel>
<Select
onValueChange={field.onChange}
value={(field.value as string) || "MA"}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select state" />
</SelectTrigger>
</FormControl>
<SelectContent>
{US_STATES.map((st) => (
<SelectItem key={st} value={st}>
{st}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="zipCode"