mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
feat(onboarding/phase-6): setup wizard polish, seed script alignment, doctor visit slots
- Setup wizard: 3-pane layout with right-side live previews, resume banner, edit/copy icons on team step, AI prompt configuration - Forms: employee-create replaces invite-member (no email invites), clinic form with address/hours/payment, doctor form with visit slots - Seed script: aligned to current SDK schema — doctors created as workspace members (HelixEngage Manager role), visitingHours replaced by doctorVisitSlot entity, clinics seeded, portalUserId linked dynamically, SUB/ORIGIN/GQL configurable via env vars - Pages: clinics + doctors CRUD updated for new schema, team settings with temp password + role assignment - New components: time-picker, day-selector, wizard-right-panes, wizard-layout-context, resume-setup-banner - Removed: invite-member-form (replaced by employee-create-form per no-email-invites rule) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -121,22 +121,44 @@ export const AppointmentForm = ({
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Fetch doctors on mount
|
||||
// Fetch doctors on mount. Doctors are hospital-wide — no single
|
||||
// `clinic` field anymore. We pull the full visit-slot list via the
|
||||
// doctorVisitSlots reverse relation so the agent can see which
|
||||
// clinics + days this doctor covers in the picker.
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
apiClient.graphql<{ doctors: { edges: Array<{ node: any }> } }>(
|
||||
`{ doctors(first: 50) { edges { node {
|
||||
id name fullName { firstName lastName } department clinic { id name clinicName }
|
||||
id name fullName { firstName lastName } department
|
||||
doctorVisitSlots(first: 50) {
|
||||
edges { node { id clinic { id clinicName } dayOfWeek startTime endTime } }
|
||||
}
|
||||
} } } }`,
|
||||
).then(data => {
|
||||
const docs = data.doctors.edges.map(e => ({
|
||||
id: e.node.id,
|
||||
name: e.node.fullName
|
||||
? `Dr. ${e.node.fullName.firstName} ${e.node.fullName.lastName}`.trim()
|
||||
: e.node.name,
|
||||
department: e.node.department ?? '',
|
||||
clinic: e.node.clinic?.clinicName ?? e.node.clinic?.name ?? '',
|
||||
}));
|
||||
const docs = data.doctors.edges.map(e => {
|
||||
// Flatten the visit-slot list into a comma-separated
|
||||
// clinic summary for display. Keep full slot data on
|
||||
// the record in case future UX needs it (e.g., show
|
||||
// only slots matching the selected date's weekday).
|
||||
const slotEdges: Array<{ node: any }> = e.node.doctorVisitSlots?.edges ?? [];
|
||||
const clinicNames = Array.from(
|
||||
new Set(
|
||||
slotEdges
|
||||
.map((se) => se.node.clinic?.clinicName)
|
||||
.filter((n): n is string => !!n),
|
||||
),
|
||||
);
|
||||
return {
|
||||
id: e.node.id,
|
||||
name: e.node.fullName
|
||||
? `Dr. ${e.node.fullName.firstName} ${e.node.fullName.lastName}`.trim()
|
||||
: e.node.name,
|
||||
department: e.node.department ?? '',
|
||||
// `clinic` here is a display-only summary: "Koramangala, Whitefield"
|
||||
// or empty if the doctor has no slots yet.
|
||||
clinic: clinicNames.join(', '),
|
||||
};
|
||||
});
|
||||
setDoctors(docs);
|
||||
}).catch(() => {});
|
||||
}, [isOpen]);
|
||||
|
||||
Reference in New Issue
Block a user