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:
83
src/components/setup/resume-setup-banner.tsx
Normal file
83
src/components/setup/resume-setup-banner.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faCircleInfo, faXmark, faArrowRight } from '@fortawesome/pro-duotone-svg-icons';
|
||||
import { Button } from '@/components/base/buttons/button';
|
||||
import { getSetupState, SETUP_STEP_NAMES, type SetupState } from '@/lib/setup-state';
|
||||
import { useAuth } from '@/providers/auth-provider';
|
||||
|
||||
// Dismissible banner shown across the top of authenticated pages when
|
||||
// the hospital workspace has incomplete setup steps AND the admin has
|
||||
// already dismissed the auto-wizard. This is the "nudge" layer —
|
||||
// a persistent reminder that setup is still outstanding, without the
|
||||
// intrusion of the full-page wizard.
|
||||
//
|
||||
// Visibility rules:
|
||||
// - Admin users only (other roles can't complete setup)
|
||||
// - At least one setup step is still `completed: false`
|
||||
// - `setup-state.wizardDismissed === true` (otherwise the wizard
|
||||
// auto-shows on next login and this banner would be redundant)
|
||||
// - Not dismissed in the current browser session (resets on reload)
|
||||
export const ResumeSetupBanner = () => {
|
||||
const { isAdmin } = useAuth();
|
||||
const [state, setState] = useState<SetupState | null>(null);
|
||||
const [dismissed, setDismissed] = useState(
|
||||
() => sessionStorage.getItem('helix_resume_setup_dismissed') === '1',
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAdmin || dismissed) return;
|
||||
getSetupState()
|
||||
.then(setState)
|
||||
.catch(() => {
|
||||
// Non-fatal — if setup-state isn't reachable, just
|
||||
// skip the banner. The wizard still works.
|
||||
});
|
||||
}, [isAdmin, dismissed]);
|
||||
|
||||
if (!isAdmin || !state || dismissed) return null;
|
||||
|
||||
const incompleteCount = SETUP_STEP_NAMES.filter((s) => !state.steps[s].completed).length;
|
||||
if (incompleteCount === 0) return null;
|
||||
|
||||
// If the wizard hasn't been dismissed yet, the first-run redirect
|
||||
// in login.tsx handles pushing the admin into /setup — no need
|
||||
// for this nudge.
|
||||
if (!state.wizardDismissed) return null;
|
||||
|
||||
const handleDismiss = () => {
|
||||
sessionStorage.setItem('helix_resume_setup_dismissed', '1');
|
||||
setDismissed(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex shrink-0 items-center justify-between gap-4 border-b border-brand bg-brand-primary px-4 py-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<FontAwesomeIcon icon={faCircleInfo} className="size-4 text-brand-primary" />
|
||||
<span className="text-sm text-primary">
|
||||
<b>Finish setting up your hospital</b> — {incompleteCount} step
|
||||
{incompleteCount === 1 ? '' : 's'} still need your attention.
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
color="primary"
|
||||
href="/setup"
|
||||
iconTrailing={({ className }: { className?: string }) => (
|
||||
<FontAwesomeIcon icon={faArrowRight} className={className} />
|
||||
)}
|
||||
>
|
||||
Resume setup
|
||||
</Button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDismiss}
|
||||
className="flex size-7 items-center justify-center rounded-md text-fg-quaternary hover:bg-secondary_hover hover:text-fg-secondary transition duration-100 ease-linear"
|
||||
title="Dismiss for this session"
|
||||
>
|
||||
<FontAwesomeIcon icon={faXmark} className="size-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user