import React, { useRef, useState } from 'react'; import type { Attachment } from 'fhir/r4'; import type { ResolvedOrgTask } from '../../utils/orgSystemTasks'; import { usePhotoUploadService } from '../../services/PhotoUploadService'; export type OnboardingTaskFocusProps = { task: ResolvedOrgTask; totalSteps: number; /** * The workspace this step lives under, when the viewer does not hold it. * * Present means the action is replaced by a sentence naming who does it. Absent is the ordinary case. */ unavailableWorkspaceNote?: string; onAction: () => void; onUploadLogo: (photo: Attachment) => Promise; onSkip: () => void; }; const LogoUploadButton = ({ label, onUpload, }: { label: string; onUpload: (photo: Attachment) => Promise; }) => { const { uploadPhoto } = usePhotoUploadService(); const inputRef = useRef(null); const [uploading, setUploading] = useState(false); const handleFileChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setUploading(true); try { const { key, contentType, size } = await uploadPhoto(file, 'org-asset'); const photo: Attachment = { // Named by key only: the server fills the bytes once this exact upload scans clean. contentType, url: key, title: file.name, size, creation: new Date().toISOString(), }; await onUpload(photo); } finally { setUploading(false); if (e.target) e.target.value = ''; } }; return ( <> ); }; const OnboardingTaskFocus = ({ task, totalSteps, unavailableWorkspaceNote, onAction, onUploadLogo, onSkip, }: OnboardingTaskFocusProps) => { const isLogo = task.action?.kind === 'modal' && task.action.modalId === 'logo'; // A step can legitimately have no button: the https step is a condition satisfied on the practice's web // host, and nothing in Akashic can change it. The footer is then not rendered at all rather than // rendered empty - an empty action row reads as a control that failed to load. const showFooter = Boolean(task.action) || !task.required; return (
Step {task.order} of {totalSteps}

{task.title}

{task.required && ( Required )}

{task.whatItDoes}

{task.whyItMatters}

{task.dependencyNote && (

{task.dependencyNote}

)} {task.checklistItems && task.checklistItems.length > 0 && (
    {task.checklistItems.map((item) => (
  • {item.completed ? '✓' : '○'} {item.label}
  • ))}
)}
{/* 🧭 CARD 697 — a step somebody else's hat owns says so, instead of offering a control that cannot work. The Platform Manager is often not an employee of the practice at all — it is the IT person or the web agency — so an admin who does not hold that hat is told who does. ⛔ What this replaces is the defect: a button that closed the dialog and changed nothing. */} {unavailableWorkspaceNote && (

This step is done in the {unavailableWorkspaceNote} workspace, which you do not have. Ask whoever manages your Akashic setup to do it.

)} {showFooter && (
{/* ⭐ The ACTION is suppressed, not the whole footer: a step somebody else owns is still one this admin may mark not-applicable, and taking Skip away with the button would strand them on it. */} {isLogo ? ( ) : ( task.action && !unavailableWorkspaceNote && ( ) )} {!task.required && ( )}
)}
); }; export default OnboardingTaskFocus;