Files
helix-engage/src/components/setup/resume-setup-banner.tsx
saridsa2 f57fbc1f24 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>
2026-04-10 08:37:34 +05:30

84 lines
3.6 KiB
TypeScript

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>
);
};