marmar-context / web / context / src / clinician / patients / NewPatient.tsx
NewPatient.tsx
Raw
import { useState } from "react";
import { clinicianApi } from "../../api/client";
import { Button, Checkbox, DialogActions, FieldError, Input, labelClass, Modal, Select } from "../kit";
import { navigate } from "../router";
import { errorText } from "../ui";

/** PAT-4: a clinic-added patient needs a name, a date of birth or age, and an attestation. */
export function NewPatient({ open, onClose }: { open: boolean; onClose: () => void }) {
  const [name, setName] = useState("");
  const [dob, setDob] = useState("");
  const [age, setAge] = useState("");
  const [sex, setSex] = useState<"" | "female" | "male">("");
  const [care, setCare] = useState(false);
  const [agreed, setAgreed] = useState(false);
  const [error, setError] = useState("");
  const [busy, setBusy] = useState(false);
  const save = async () => {
    if (name.trim().split(/\s+/).length < 2) return setError("Enter the patient's full name.");
    if (!dob && !age) return setError("Enter a date of birth or an age.");
    setBusy(true);
    setError("");
    try {
      const p = await clinicianApi.createPatient({
        name: name.trim(),
        dateOfBirth: dob || null,
        age: dob ? null : Number(age),
        sex: sex || null,
        attestation: { careRelationship: true, patientAgreed: true },
      });
      navigate(`/app/patients/${p.id}/check`);
    } catch (e) {
      setError(errorText(e));
    } finally {
      setBusy(false);
    }
  };
  return (
    <Modal open={open} title="Add a patient" onClose={onClose}>
      <p className="m-0">For a patient who has not invited you from MARMAR Health. You add their records yourself.</p>
      <label className={labelClass}>
        Full name
        <Input value={name} onChange={(e) => setName(e.target.value)} autoComplete="off" />
      </label>
      <div className="grid gap-3 sm:grid-cols-2">
        <label className={labelClass}>
          Date of birth
          <Input type="date" value={dob} onChange={(e) => setDob(e.target.value)} />
        </label>
        <label className={labelClass}>
          Or age
          <Input inputMode="numeric" value={age} disabled={!!dob} onChange={(e) => setAge(e.target.value.replace(/\D/g, "").slice(0, 3))} />
        </label>
      </div>
      <label className={labelClass}>
        Sex, only if you know it
        <Select value={sex} onChange={(e) => setSex(e.target.value as typeof sex)}>
          <option value="">Not recorded</option>
          <option value="female">Female</option>
          <option value="male">Male</option>
        </Select>
      </label>
      <div className="flex flex-col gap-2.5">
        <Checkbox checked={care} onChange={(e) => setCare(e.target.checked)}>
          I have a care relationship with this patient.
        </Checkbox>
        <Checkbox checked={agreed} onChange={(e) => setAgreed(e.target.checked)}>
          The patient agreed to my using Context for their records.
        </Checkbox>
      </div>
      {error && <FieldError>{error}</FieldError>}
      <DialogActions>
        <Button onClick={onClose}>Cancel</Button>
        <Button variant="primary" disabled={!care || !agreed || busy} onClick={() => void save()}>
          {busy ? "Adding…" : "Add patient"}
        </Button>
      </DialogActions>
    </Modal>
  );
}