Files
Khalid Abdi 90e6ec4cc0 feat: email provider, admin password reset, portal new-patient, chat pill
Chat: history pill now shows a History icon + a Start-new-chat (SquarePen)
button; removed the duplicate chat-history list from the sidebar.

Email: deployment-wide email provider config (Resend/Postmark/SendGrid/SMTP) in
Settings → Developers, with encrypted API key and a Send-test action. sendEmail
dispatches via the chosen provider (REST via fetch; SMTP via nodemailer).

Forgot password with no provider: alert the clinic admin(s) via a "System"
message card in Messages + a bell notification (seeded system user + per-clinic
System conversation); clicking deep-links to /settings?tab=careTeam&member=<id>.
Admins can set a member's password directly from the employee dialog
(PATCH /api/staff/:id/password via Better Auth's internal context — no admin
plugin needed).

Patient Portal: "New patient" booking path registers a demographics-only patient
then books; bookings reject double-booked slots (409).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 19:52:55 +03:00

73 lines
2.1 KiB
TypeScript

import { apiFetch } from "@/lib/api-client";
// A clinician who can be assigned as a patient's primary provider. Returned by
// the backend's GET /api/staff/providers (clinical roles only — excludes
// reception/pharmacy/lab). Readable by any clinic member.
export type Provider = {
userId: string;
name: string;
role: string;
// Admin-set clinical specialty (e.g. "Orthopedist"); null when unset.
specialty?: string | null;
};
export function listProviders(): Promise<Provider[]> {
return apiFetch<Provider[]>("/api/staff/providers");
}
// Set a member's password directly (owner/admin only) — used when an employee
// forgot it and no email provider is configured.
export function setStaffPassword(
userId: string,
newPassword: string,
): Promise<{ ok: boolean }> {
return apiFetch(`/api/staff/${encodeURIComponent(userId)}/password`, {
method: "PATCH",
body: JSON.stringify({ newPassword }),
});
}
// Update a member's clinical specialty (owner/admin only). Pass null to clear.
export function updateStaffSpecialty(
userId: string,
specialty: string | null,
): Promise<{ userId: string; specialty: string | null }> {
return apiFetch(`/api/staff/${encodeURIComponent(userId)}`, {
method: "PATCH",
body: JSON.stringify({ specialty }),
});
}
// Curated list of clinical specialties an admin can assign to a doctor. Stored
// as the plain string; values double as the i18n key suffix
// (settings.careTeam.specialties.*).
// Human label for a stored specialty key (settings.careTeam.specialties.*),
// falling back to the raw value for any legacy/free-text entries.
export function specialtyLabel(
t: (key: string) => string,
specialty?: string | null,
): string | null {
if (!specialty) return null;
const key = `settings.careTeam.specialties.${specialty}`;
const label = t(key);
return label === key ? specialty : label;
}
export const SPECIALTIES = [
"general",
"orthopedics",
"dentistry",
"cardiology",
"pediatrics",
"dermatology",
"neurology",
"obgyn",
"ophthalmology",
"ent",
"psychiatry",
"radiology",
"anesthesiology",
"surgery",
] as const;
export type Specialty = (typeof SPECIALTIES)[number];