import { useState } from "react";
import { clinicianApi } from "../../api/client";
import type { IdleMinutes } from "../../api/types";
import { Button, Checkbox, ChoiceChips, DialogActions, Hint, Icon, Modal, Panel } from "../kit";
import { askForNotifications, notificationsSupported } from "../notify";
import { navigate } from "../router";
import { useClinician } from "../session";
import { errorText } from "../ui";
/** ACC-7: the idle lock, Lock now and Sign out everywhere. */
export function SecuritySection({ onSaved }: { onSaved: (message: string, warn?: boolean) => void }) {
const { me, setMe, lock } = useClinician();
const [everywhere, setEverywhere] = useState(false);
const setIdle = async (minutes: IdleMinutes) => {
try {
setMe(await clinicianApi.updateMe({ idleLockMinutes: minutes }));
onSaved(`Context now locks after ${minutes} minutes without activity.`);
} catch (e) {
onSaved(errorText(e), true);
}
};
return (
<>
<Panel title="Lock" icon="lock-line" iconClass="text-indigo-icon">
<ChoiceChips<IdleMinutes>
legend="Lock Context after this long without activity"
name="idle"
describedBy="idle-help"
options={([15, 30, 60] as IdleMinutes[]).map((m) => ({ value: m, label: `${m} minutes` }))}
value={me.idleLockMinutes}
onChange={(m) => void setIdle(m)}
/>
<Hint id="idle-help">Locking hides patient data until you enter your authenticator code. Sessions end after 12 hours.</Hint>
<div>
<Button onClick={lock}>
<Icon name="lock-line" size={15} /> Lock now
</Button>
</div>
</Panel>
<Panel title="Sessions" icon="shield-keyhole-line" iconClass="text-teal-icon">
<p className="m-0 text-[13.5px] leading-5 text-body">Signed in somewhere you no longer use, or lost a device? End every session for your account at once.</p>
<div>
<Button onClick={() => setEverywhere(true)}>
<Icon name="logout-box-r-line" size={15} /> Sign out everywhere
</Button>
</div>
</Panel>
<Modal open={everywhere} title="Sign out everywhere" onClose={() => setEverywhere(false)}>
<p className="m-0">This ends every Context session for your account, on every device, including this one.</p>
<DialogActions>
<Button onClick={() => setEverywhere(false)}>Cancel</Button>
<Button
variant="primary"
onClick={async () => {
await clinicianApi.signOutEverywhere().catch(() => undefined);
navigate("/sign-in?reason=signed-out", { replace: true });
}}
>
Sign out everywhere
</Button>
</DialogActions>
</Modal>
</>
);
}
/** NTF-2: browser notifications are this browser's choice; email always reaches the clinician. */
export function NotificationsSection({ onSaved }: { onSaved: (message: string, warn?: boolean) => void }) {
const { me, setMe } = useClinician();
const supported = notificationsSupported();
const setBrowser = async (on: boolean) => {
const allowed = on ? await askForNotifications() : true;
if (on && !allowed) return onSaved("The browser blocked notifications. Allow them in the site settings, then try again.", true);
try {
setMe(await clinicianApi.updateMe({ notifications: { ...me.notifications, browser: on } }));
} catch (e) {
onSaved(errorText(e), true);
}
};
return (
<Panel title="Notifications" icon="notification-3-line" iconClass="text-pink-icon">
<Checkbox checked={me.notifications.browser} disabled={!supported} aria-describedby="notify-help" onChange={(e) => void setBrowser(e.target.checked)}>
Browser notifications for urgent notes and finished check-ins {!supported && "(not supported in this browser)"}
</Checkbox>
<Hint id="notify-help">
Notifications name the patient at most, never health details. Urgent notes and finished check-ins reach you by email; urgent notes will also come by SMS once MARMAR
sends SMS.
</Hint>
</Panel>
);
}