marmar-context / web / context / test / fixture / wire.ts
wire.ts
Raw
// 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 } };
}