Files
helix-engage/scripts/seed-new-entities.ts
saridsa2 61901eb8fb feat: wire frontend to platform data, migrate to Jotai + Vercel AI SDK
- Replace mock DataProvider with real GraphQL queries through sidecar
- Add queries.ts and transforms.ts for platform field name mapping
- Migrate SIP state from React Context to Jotai atoms (React 19 compat)
- Add singleton SIP manager to survive StrictMode remounts
- Remove hardcoded Olivia/Sienna accounts from nav menu
- Add password eye toggle, remember me checkbox, forgot password link
- Fix worklist hook to transform platform field names
- Add seed scripts for clinics, health packages, lab tests
- Update test harness for new doctor→clinic relation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:44:45 +05:30

349 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Seed clinics, health packages, insurance partners, and link doctors to clinics.
* Run: cd helix-engage && npx tsx scripts/seed-new-entities.ts
*
* Prerequisites: doctors already seeded via seed-data.ts
*
* Platform field mapping (SDK name → platform name):
* Clinic: address→addressCustom, operatingHoursWeekday→weekdayHours,
* operatingHoursSaturday→saturdayHours, operatingHoursSunday→sundayHours,
* clinicStatus→status, onlineBookingEnabled→onlineBooking,
* arriveEarlyMinutes→arriveEarlyMin, paymentCash→acceptsCash,
* paymentCard→acceptsCard, paymentUpi→acceptsUpi
* HealthPackage: packageDepartment→department, durationMinutes→durationMin, isActive→active
* InsurancePartner: planTypes→planTypesAccepted
*/
const GQL = 'http://localhost:4000/graphql';
const SUB = 'fortytwo-dev';
const ORIGIN = 'http://fortytwo-dev.localhost:4010';
let token = '';
async function gql(query: string, variables?: any) {
const h: Record<string, string> = { 'Content-Type': 'application/json', 'X-Workspace-Subdomain': SUB };
if (token) h['Authorization'] = `Bearer ${token}`;
const r = await fetch(GQL, { method: 'POST', headers: h, body: JSON.stringify({ query, variables }) });
const d: any = await r.json();
if (d.errors) { console.error('❌', d.errors[0].message); throw new Error(d.errors[0].message); }
return d.data;
}
async function auth() {
const d1 = await gql(`mutation { getLoginTokenFromCredentials(email: "dev@fortytwo.dev", password: "tim@apple.dev", origin: "${ORIGIN}") { loginToken { token } } }`);
const lt = d1.getLoginTokenFromCredentials.loginToken.token;
const d2 = await gql(`mutation { getAuthTokensFromLoginToken(loginToken: "${lt}", origin: "${ORIGIN}") { tokens { accessOrWorkspaceAgnosticToken { token } } } }`);
token = d2.getAuthTokensFromLoginToken.tokens.accessOrWorkspaceAgnosticToken.token;
}
async function mk(entity: string, data: any): Promise<string> {
const cap = entity[0].toUpperCase() + entity.slice(1);
const d = await gql(`mutation($data: ${cap}CreateInput!) { create${cap}(data: $data) { id } }`, { data });
return d[`create${cap}`].id;
}
async function update(entity: string, id: string, data: any): Promise<void> {
const cap = entity[0].toUpperCase() + entity.slice(1);
await gql(`mutation($id: UUID!, $data: ${cap}UpdateInput!) { update${cap}(id: $id, data: $data) { id } }`, { id, data });
}
async function main() {
console.log('🌱 Seeding clinics, health packages, insurance partners...\n');
await auth();
console.log('✅ Auth OK\n');
// ═══════════════════════════════════════════
// CLINICS
// ═══════════════════════════════════════════
console.log('🏥 Clinics');
const koramangala = await mk('clinic', {
name: 'Global Hospital — Koramangala',
clinicName: 'Koramangala',
addressCustom: {
addressStreet1: '#45, 80 Feet Road',
addressCity: 'Bengaluru',
addressState: 'Karnataka',
addressPostcode: '560034',
addressCountry: 'India',
},
phone: { primaryPhoneNumber: '08041234567', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
email: { primaryEmail: 'koramangala@globalhospital.com' },
weekdayHours: '8:00 AM 8:00 PM',
saturdayHours: '8:00 AM 8:00 PM',
sundayHours: '9:00 AM 2:00 PM',
status: 'ACTIVE',
walkInAllowed: true,
onlineBooking: true,
cancellationWindowHours: 4,
arriveEarlyMin: 15,
requiredDocuments: 'ID proof + medical records',
acceptsCash: 'YES',
acceptsCard: 'YES',
acceptsUpi: 'YES',
});
console.log(` Koramangala: ${koramangala}`);
const whitefield = await mk('clinic', {
name: 'Global Hospital — Whitefield',
clinicName: 'Whitefield',
addressCustom: {
addressStreet1: 'Prestige Shantiniketan',
addressCity: 'Bengaluru',
addressState: 'Karnataka',
addressPostcode: '560048',
addressCountry: 'India',
},
phone: { primaryPhoneNumber: '08041234568', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
email: { primaryEmail: 'whitefield@globalhospital.com' },
weekdayHours: '8:00 AM 8:00 PM',
saturdayHours: '8:00 AM 8:00 PM',
sundayHours: 'Closed',
status: 'ACTIVE',
walkInAllowed: true,
onlineBooking: true,
cancellationWindowHours: 4,
arriveEarlyMin: 15,
requiredDocuments: 'ID proof + medical records',
acceptsCash: 'YES',
acceptsCard: 'YES',
acceptsUpi: 'YES',
});
console.log(` Whitefield: ${whitefield}`);
const indiranagar = await mk('clinic', {
name: 'Global Hospital — Indiranagar',
clinicName: 'Indiranagar',
addressCustom: {
addressStreet1: '#12, 100 Feet Road',
addressCity: 'Bengaluru',
addressState: 'Karnataka',
addressPostcode: '560038',
addressCountry: 'India',
},
phone: { primaryPhoneNumber: '08041234569', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
email: { primaryEmail: 'indiranagar@globalhospital.com' },
weekdayHours: '9:00 AM 7:00 PM',
saturdayHours: '9:00 AM 7:00 PM',
sundayHours: '10:00 AM 1:00 PM',
status: 'ACTIVE',
walkInAllowed: true,
onlineBooking: true,
cancellationWindowHours: 4,
arriveEarlyMin: 15,
requiredDocuments: 'ID proof + medical records',
acceptsCash: 'YES',
acceptsCard: 'YES',
acceptsUpi: 'YES',
});
console.log(` Indiranagar: ${indiranagar}\n`);
await auth();
// ═══════════════════════════════════════════
// LINK DOCTORS TO CLINICS
// ═══════════════════════════════════════════
console.log('🔗 Linking doctors to clinics');
const doctors: Record<string, string> = {
'da5678f3-6b52-492e-87d3-c4707d105938': 'Dr. Sharma', // Koramangala
'b080cdf0-4527-46c7-b723-47f2eee623e4': 'Dr. Patel', // Indiranagar
'd780976a-7ddb-4a00-9a56-e7e3a77fa416': 'Dr. Kumar', // Whitefield
'bf77c148-438f-4b6f-9e5d-b1c1ff2e10f8': 'Dr. Reddy', // Koramangala
'e71c2c59-574f-4e81-b8cd-2d7b4b5da8e5': 'Dr. Singh', // Indiranagar
};
const doctorClinicMap: Record<string, string> = {
'da5678f3-6b52-492e-87d3-c4707d105938': koramangala,
'b080cdf0-4527-46c7-b723-47f2eee623e4': indiranagar,
'd780976a-7ddb-4a00-9a56-e7e3a77fa416': whitefield,
'bf77c148-438f-4b6f-9e5d-b1c1ff2e10f8': koramangala,
'e71c2c59-574f-4e81-b8cd-2d7b4b5da8e5': indiranagar,
};
for (const [docId, clinicId] of Object.entries(doctorClinicMap)) {
await update('doctor', docId, { clinicId });
console.log(` ${doctors[docId]}${clinicId === koramangala ? 'Koramangala' : clinicId === whitefield ? 'Whitefield' : 'Indiranagar'}`);
}
console.log('');
await auth();
// ═══════════════════════════════════════════
// HEALTH PACKAGES
// ═══════════════════════════════════════════
console.log('📦 Health Packages');
await mk('healthPackage', {
name: 'Master Health Checkup',
packageName: 'Master Health Checkup',
description: 'Comprehensive annual health screening — blood work, ECG, chest X-ray, BMI, vision, dental',
price: { amountMicros: 2_999_000_000, currencyCode: 'INR' },
department: 'PREVENTIVE',
inclusions: 'CBC, Lipid Profile, Liver Function, Kidney Function, Thyroid, Blood Sugar, ECG, Chest X-ray, BMI, Vision Test, Dental Check',
durationMin: 180,
eligibility: 'All adults above 18 years',
active: true,
clinicId: koramangala,
});
console.log(' Master Health Checkup — ₹2,999');
await mk('healthPackage', {
name: 'Cardiac Screening',
packageName: 'Cardiac Screening',
description: 'Heart health assessment — ECG, Echo, TMT, lipid panel, cardiac risk markers',
price: { amountMicros: 4_999_000_000, currencyCode: 'INR' },
department: 'CARDIOLOGY',
inclusions: 'ECG, 2D Echocardiogram, TMT (Treadmill Test), Lipid Profile, hs-CRP, Homocysteine, HbA1c, Cardiologist Consultation',
durationMin: 240,
eligibility: 'Adults above 30 or family history of heart disease',
active: true,
clinicId: koramangala,
});
console.log(' Cardiac Screening — ₹4,999');
await mk('healthPackage', {
name: "Women's Wellness Package",
packageName: "Women's Wellness Package",
description: 'Complete women\'s health screening — PAP smear, mammogram, hormone panel, bone density',
price: { amountMicros: 3_499_000_000, currencyCode: 'INR' },
department: 'GYNECOLOGY',
inclusions: 'PAP Smear, Mammogram, Pelvic Ultrasound, Thyroid Panel, Vitamin D, Calcium, CBC, Hormone Panel (FSH/LH/Estradiol), Bone Density Scan, Gynecologist Consultation',
durationMin: 210,
eligibility: 'Women above 25 years',
active: true,
clinicId: indiranagar,
});
console.log(" Women's Wellness — ₹3,499");
await mk('healthPackage', {
name: 'Orthopedic Assessment',
packageName: 'Orthopedic Assessment',
description: 'Joint and bone health evaluation — X-rays, bone density, vitamin levels, specialist consult',
price: { amountMicros: 1_999_000_000, currencyCode: 'INR' },
department: 'ORTHOPEDICS',
inclusions: 'Joint X-rays (knee/hip/spine), Bone Density Scan, Vitamin D, Calcium, Uric Acid, RA Factor, Orthopedic Consultation',
durationMin: 120,
eligibility: 'Adults with joint pain or age above 40',
active: true,
clinicId: whitefield,
});
console.log(' Orthopedic Assessment — ₹1,999');
await mk('healthPackage', {
name: 'IVF Consultation Package',
packageName: 'IVF Consultation Package',
description: 'Initial fertility assessment — hormone panel, ultrasound, semen analysis, specialist consult',
price: { amountMicros: 5_999_000_000, currencyCode: 'INR' },
discountedPrice: { amountMicros: 0, currencyCode: 'INR' },
department: 'GYNECOLOGY',
inclusions: 'AMH, FSH, LH, Estradiol, Prolactin, Thyroid Panel, Transvaginal Ultrasound, Semen Analysis, Fertility Specialist Consultation',
durationMin: 150,
eligibility: 'Couples planning IVF or facing infertility (1+ year)',
active: true,
clinicId: indiranagar,
});
console.log(' IVF Consultation — ₹5,999 (free first visit via campaign)\n');
await auth();
// ═══════════════════════════════════════════
// INSURANCE PARTNERS
// ═══════════════════════════════════════════
console.log('🛡️ Insurance Partners');
await mk('insurancePartner', {
name: 'Star Health Insurance',
insurerName: 'Star Health',
tpaName: 'Star Health & Allied Insurance',
planTypesAccepted: 'Family Health Optima, Comprehensive, Senior Citizen Red Carpet',
settlementType: 'BOTH',
empanelmentStatus: 'ACTIVE',
validUntil: '2027-03-31',
contactPerson: 'Rajesh M',
contactPhone: { primaryPhoneNumber: '9900200001', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
clinicId: koramangala,
});
console.log(' Star Health — cashless + reimbursement');
await mk('insurancePartner', {
name: 'ICICI Lombard',
insurerName: 'ICICI Lombard',
tpaName: 'Medi Assist',
planTypesAccepted: 'iHealth, Complete Health Insurance, Group Mediclaim',
settlementType: 'CASHLESS',
empanelmentStatus: 'ACTIVE',
validUntil: '2027-06-30',
contactPerson: 'Priya K',
contactPhone: { primaryPhoneNumber: '9900200002', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
clinicId: koramangala,
});
console.log(' ICICI Lombard — cashless');
await mk('insurancePartner', {
name: 'Bajaj Allianz',
insurerName: 'Bajaj Allianz',
tpaName: 'Health India TPA',
planTypesAccepted: 'Health Guard, Silver Health, Group Health',
settlementType: 'BOTH',
empanelmentStatus: 'ACTIVE',
validUntil: '2027-01-31',
contactPerson: 'Suresh V',
contactPhone: { primaryPhoneNumber: '9900200003', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
clinicId: whitefield,
});
console.log(' Bajaj Allianz — cashless + reimbursement');
await mk('insurancePartner', {
name: 'HDFC Ergo',
insurerName: 'HDFC Ergo',
tpaName: 'Paramount Health Services',
planTypesAccepted: 'Optima Secure, Optima Restore, My Health Suraksha',
settlementType: 'CASHLESS',
empanelmentStatus: 'ACTIVE',
validUntil: '2027-09-30',
contactPerson: 'Anita S',
contactPhone: { primaryPhoneNumber: '9900200004', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
clinicId: indiranagar,
});
console.log(' HDFC Ergo — cashless');
await mk('insurancePartner', {
name: 'Niva Bupa (Max Bupa)',
insurerName: 'Niva Bupa',
tpaName: 'Niva Bupa Health Insurance',
planTypesAccepted: 'Health Recharge, Health Premia, ReAssure 2.0',
settlementType: 'BOTH',
empanelmentStatus: 'ACTIVE',
validUntil: '2027-04-30',
contactPerson: 'Deepak R',
contactPhone: { primaryPhoneNumber: '9900200005', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
clinicId: koramangala,
});
console.log(' Niva Bupa — cashless + reimbursement');
await mk('insurancePartner', {
name: 'New India Assurance',
insurerName: 'New India Assurance',
tpaName: 'Raksha TPA',
planTypesAccepted: 'Mediclaim Policy, Jan Arogya Bima, Group Mediclaim',
settlementType: 'REIMBURSEMENT',
empanelmentStatus: 'ACTIVE',
validUntil: '2027-12-31',
contactPerson: 'Mohan T',
contactPhone: { primaryPhoneNumber: '9900200006', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' },
clinicId: whitefield,
});
console.log(' New India Assurance — reimbursement\n');
// ═══════════════════════════════════════════
// CLEANUP: Delete the empty doctor record
// ═══════════════════════════════════════════
try {
await gql(`mutation { deleteDoctor(id: "967e1959-9b85-497e-9f8e-cad65120c5de") { id } }`);
console.log('🧹 Cleaned up empty doctor record\n');
} catch {
// Ignore if already deleted
}
console.log('🎉 Done!');
console.log(' 3 clinics · 5 health packages · 6 insurance partners');
console.log(' 5 doctors linked to clinics');
}
main().catch(e => { console.error('💥', e.message); process.exit(1); });