feat: fix DDMA eligibility — patient list, name extraction, PDF page, OTP session

- Filter patient list by userId so each user sees only their own patients
- Sort patients by updatedAt DESC so recently checked patients appear first
- Add updatedAt field to Patient model (DB migration via raw SQL + db:generate)
- Fix DDMA name extraction: read from detail page "Name:" label, not search
  results row text which included appended dates
- Fix PDF capture: use driver.get() instead of click() to avoid race condition
  that was saving the search results page instead of the patient detail page
- Strip trailing bare dates from extracted names (e.g. "Rodriguez 04/27/2026")
- Handle "Last, First" comma format and single-word last names in splitName
- Normalize insuranceId consistently in createOrUpdatePatientByInsuranceId
- Fix OTP persistent session: stop clearing LocalStorage/IndexedDB on startup
  (these hold the DDMA device trust token that skips OTP on subsequent logins)
- Increase post-navigation wait time for full page render before PDF generation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-01 21:40:04 -04:00
parent 24bbaed6ab
commit e26ebf7fd5
213 changed files with 1698 additions and 1425 deletions

View File

@@ -94,10 +94,16 @@ export async function createOrUpdatePatientByInsuranceId(options: {
const { insuranceId, firstName, lastName, dob, userId } = options;
if (!insuranceId) throw new Error("Missing insuranceId");
// Normalize insuranceId the same way insertPatientSchema does (strip spaces)
const normalizedId = insuranceId.replace(/\s+/g, "");
const incomingFirst = (firstName || "").trim();
const incomingLast = (lastName || "").trim();
let patient = await storage.getPatientByInsuranceId(insuranceId);
console.log(`[createOrUpdatePatient] insuranceId="${normalizedId}" firstName="${incomingFirst}" lastName="${incomingLast}" userId=${userId}`);
let patient = await storage.getPatientByInsuranceId(normalizedId);
console.log(`[createOrUpdatePatient] existing patient lookup: ${patient ? `found id=${patient.id}` : "not found"}`);
if (patient && patient.id) {
const updates: any = {};
@@ -110,8 +116,9 @@ export async function createOrUpdatePatientByInsuranceId(options: {
if (!isNaN(parsed.getTime())) updates.dateOfBirth = parsed;
}
if (Object.keys(updates).length > 0) {
console.log(`[createOrUpdatePatient] updating patient id=${patient.id} with`, updates);
await storage.updatePatient(patient.id, updates);
patient = await storage.getPatientByInsuranceId(insuranceId);
patient = await storage.getPatientByInsuranceId(normalizedId);
}
return patient;
}
@@ -123,24 +130,31 @@ export async function createOrUpdatePatientByInsuranceId(options: {
gender: "",
phone: "",
userId,
insuranceId,
insuranceId: normalizedId,
};
let patientData: InsertPatient;
try {
patientData = insertPatientSchema.parse(createPayload);
} catch {
// Remove fields that may fail validation (invalid date or alphanumeric insuranceId)
} catch (e1) {
console.warn(`[createOrUpdatePatient] schema parse failed (attempt 1):`, e1);
const safePayload = { ...createPayload };
delete safePayload.dateOfBirth;
try {
patientData = insertPatientSchema.parse(safePayload);
} catch {
// Last resort: skip schema validation and cast directly
} catch (e2) {
console.warn(`[createOrUpdatePatient] schema parse failed (attempt 2):`, e2);
patientData = safePayload as InsertPatient;
}
}
await storage.createPatient(patientData);
return storage.getPatientByInsuranceId(insuranceId);
try {
await storage.createPatient(patientData);
console.log(`[createOrUpdatePatient] patient created successfully for insuranceId="${normalizedId}"`);
} catch (dbErr: any) {
console.error(`[createOrUpdatePatient] DB create failed:`, dbErr?.message ?? dbErr);
throw dbErr;
}
return storage.getPatientByInsuranceId(normalizedId);
}