// The fixture keeps its people in Context's view types and answers in the backend's own JSON // (src/api/wire.ts), so fixture mode runs through the same client and adapters as the real API. import { toWireDay, wireHours } from "../../src/api/adapt"; import type * as T from "../../src/api/types"; import type * as W from "../../src/api/wire"; import type { StoredExtraction } from "./clinical"; import type { StoredRecord } from "./data"; const TWELVE_HOURS = 12 * 3_600_000; export function wireClinician(c: T.ClinicianProfile): W.Clinician { return { id: c.id, email: c.email, fullName: c.fullName, title: c.title || null, displayName: c.spokenName, pronoun: c.pronoun, profession: c.profession, licenceBody: c.licensingBody, licenceNumber: c.licenceNumber, countryCode: "NG", mobilePhone: c.mobilePhone, status: "verified", verifiedAt: c.verifiedAt, verificationExpiresAt: c.licenceExpiresAt ? `${c.licenceExpiresAt.slice(0, 10)}T00:00:00.000Z` : "2027-10-01T00:00:00.000Z", idleLockMinutes: c.idleLockMinutes, termsVersion: c.termsAcceptedAt ? "clinician-terms-2026-10" : null, termsAcceptedAt: c.termsAcceptedAt, dpaVersion: c.termsAcceptedAt ? "context-dpa-2026-10" : null, dpaAcceptedAt: c.termsAcceptedAt, }; } export function wireMe( c: T.ClinicianProfile, s: { createdAt: number; stepUp: boolean; locked: boolean }, totp: boolean, ): W.Me { return { clinician: { ...wireClinician(c), lapsed: false }, session: { stepUpDone: s.stepUp && !s.locked, locked: s.locked, idleLockMinutes: c.idleLockMinutes, startedAt: new Date(s.createdAt).toISOString(), endsAt: new Date(s.createdAt + TWELVE_HOURS).toISOString(), }, secondFactor: { totp }, features: { realPatients: true, invites: true, checkIns: true }, }; } export function wireClinic(c: T.ClinicProfile): W.Clinic { return { id: c.id, name: c.name, addressLine: c.address || null, city: null, region: null, countryCode: c.country, timezone: c.timeZone, phone: c.phone || null, openingHours: wireHours(c.openingHours), alertWatchHours: wireHours(c.alertWatchHours), backupAlertName: c.backupContact?.name ?? null, backupAlertPhone: c.backupContact?.phone ?? null, backupAlertEmail: c.backupContact?.email || null, version: c.version, updatedAt: new Date().toISOString(), role: c.role, emergencyNumbers: c.emergencyNumbers.map((n) => ({ number: n.number, label: n.label, source: n.source, testDialledAt: n.testedAt })), }; } const wireSharing = (s: T.Sharing | null): W.Sharing | null => s ? { status: s.status, scopes: s.scopes, allowsCheckInCalls: s.allowsCheckInCalls, changedAt: s.changedAt, sharedBy: s.status === "connected" ? s.sharedBy : [], withheldSome: s.status === "connected" && s.withheldSome } : null; /** As the backend's list item: the tile's counts and last check-in only while sharing is on (SHR-1). */ export function wireItem(d: T.PatientDetail, lastCheckAt: string | null = null): W.PatientItem { return { id: d.id, kind: d.kind, clinicId: "clinic-surulere", displayName: d.name, dateOfBirth: d.dateOfBirth ? `${d.dateOfBirth}T00:00:00.000Z` : null, birthYear: d.birthYear, ageYears: d.dateOfBirth ? null : d.age, ageRecordedOn: null, sex: d.sex, shareId: d.kind === "connected" ? `share-${d.id}` : null, lastActivityAt: d.lastActivityAt, createdAt: d.lastActivityAt, name: d.name, age: d.age, attention: d.attention, lastCheckId: d.lastCheckId, lastCheckAt, newInformation: d.newInformation, sharing: wireSharing(d.sharing), medicines: d.sharing?.status === "connected" ? d.medicines : null, doses: d.sharing?.status === "connected" ? d.doses : null, lastCheckIn: d.sharing?.status === "connected" ? d.lastCheckIn : null, }; } /** As the backend's detail today: the app-side fields come from the shared tile and the plan instead. */ export const wireDetail = (d: T.PatientDetail, lastCheckAt: string | null = null): W.PatientDetail => ({ ...wireItem(d, lastCheckAt), firstName: d.firstName, dateOfBirthIso: d.dateOfBirth, identityOnFile: d.identityOnFile, timeZone: "Africa/Lagos", hasOwnAccount: false, phone: null, pronoun: null, preferredTitle: null, activeCheckInId: null, }); export const wireTile = (d: T.PatientDetail): W.SharedSummary => ({ asOf: new Date().toISOString(), sharing: { status: "connected", sharedBy: d.sharing?.sharedBy ?? [], scopes: d.sharing?.scopes ?? [], allowsCheckInCalls: !!d.sharing?.allowsCheckInCalls, withheldSome: !!d.sharing?.withheldSome, changedAt: d.sharing?.changedAt ?? new Date().toISOString() }, medicines: d.medicines, doses: d.doses, lastCheckIn: d.lastCheckIn, phone: d.phone, }); export const wireInvitation = ({ patientPronoun: _p, ...rest }: T.Invitation): W.Invitation => rest; export function wireRecord(r: StoredRecord): W.Record_ { const { text: _text, clarifies, ...rest } = r; return { ...rest, fileName: null, origin: clarifies ? "pasted" : r.origin }; } export function wireExtraction(ex: StoredExtraction, stale: boolean): W.Extraction { const { sources: _sources, titles: _titles, ...rest } = ex; return { ...rest, records: ex.records.map((r) => ({ recordId: r.recordId, status: r.status, error: r.error, inReading: true })), stale, coverage: (ex.coverage ?? []).map((c) => ({ ...c, kind: c.kind ?? "medicine" })), }; } export const wireCheck = (c: T.CheckRun, latest: boolean): W.CheckRun => ({ ...c, summary: c.summary!, latest, profile: [], medicines: [], sourceLines: [], }); export function wirePlan(p: T.CheckInPlanTemplate, eligible: boolean): W.PlanTemplate { const w = p.window; return { ...p, window: w.known ? { patientTimeZone: w.patientTimeZone, clinicTimeZone: w.clinicTimeZone, clinicHours: wireHours(w.clinicHours), alertWatchHours: wireHours(w.alertWatchHours), dayStart: w.dayStart, dayEnd: w.dayEnd, quietHours: w.quietHours.start === w.quietHours.end ? null : w.quietHours, blockedTimes: w.blockedTimes.map((b) => ({ ...b, day: b.day === null ? null : toWireDay(b.day) })), defaultExpiryHours: w.defaultExpiryHours, maxExpiryHours: w.maxExpiryHours, } : { patientTimeZone: null, clinicTimeZone: w.clinicTimeZone, quietHours: { start: "22:00", end: "07:00" }, defaultExpiryHours: w.defaultExpiryHours, maxExpiryHours: w.maxExpiryHours }, limits: eligible || p.eligibility.code === "limit_reached" || p.eligibility.code === "active_check_in" ? p.limits : null, }; } export function wireCheckIn(c: T.CheckIn, script: W.CheckIn["script"]): W.CheckIn { const { alerts: _alerts, plan, ...rest } = c; const { linkedTiers: _tiers, ...wirePlanFields } = plan; return { ...rest, plan: wirePlanFields, script, window: c.window ?? { start: c.requestedAt, end: plan.expiresAt } }; }