backend: add per-clinic staff specialty (Care Team -> patient sheet)

New staff_profile table (org + user, unique) holding a clinician's clinical
specialty. GET /api/staff and /api/staff/providers now include specialty; new
PATCH /api/staff/:userId (member:update) upserts it. Migration 0023.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-19 20:28:52 +03:00
parent eb94c1549a
commit 2f36875d37
12 changed files with 4156 additions and 48 deletions
@@ -1506,6 +1506,22 @@
"clickHint": "Tip: click a team member to see their permissions and manage their role.",
"addMember": "Add team member",
"removeMember": "Remove member",
"specialties": {
"general": "General practitioner",
"orthopedics": "Orthopedist",
"dentistry": "Dentist",
"cardiology": "Cardiologist",
"pediatrics": "Pediatrician",
"dermatology": "Dermatologist",
"neurology": "Neurologist",
"obgyn": "OB-GYN",
"ophthalmology": "Ophthalmologist",
"ent": "ENT specialist",
"psychiatry": "Psychiatrist",
"radiology": "Radiologist",
"anesthesiology": "Anesthesiologist",
"surgery": "Surgeon"
},
"employee": {
"title": "Team member",
"description": "View this member's access, change their role, or remove them.",
@@ -1520,6 +1536,12 @@
"roleUpdatedBody": "{{name}} is now {{role}}.",
"roleFailedTitle": "Couldn't update role",
"roleFailedBody": "Please try again.",
"specialty": "Specialty",
"noSpecialty": "No specialty",
"specialtyUpdatedTitle": "Specialty updated",
"specialtyUpdatedBody": "Updated {{name}}'s specialty.",
"specialtyFailedTitle": "Couldn't update specialty",
"specialtyFailedBody": "Please try again.",
"resources": {
"patient": "Patients",
"appointment": "Appointments",
+46
View File
@@ -7,8 +7,54 @@ 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");
}
// 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];