// 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 } };
}