feat: add company builder wizard with AI-powered org generation (#73)
* feat: add company builder wizard with AI-powered org generation Adds a new "Build Your Company" step to the onboarding wizard that lets users describe their business and generates a full agent org structure using OpenClaw's AI. Includes company plan generation, role deduplication, agent bootstrap with main-agent reuse, org chart preview, confetti on success, CSS voxel running-avatar loader, amber theme unification, and best-effort SSH workspace cleanup. Made-with: Cursor * fix: resolve lint errors in CompanyBuilderModal Replace setState-in-effect pattern with a direct callback, escape apostrophes in JSX text, and derive org chart hover state without side effects. Made-with: Cursor --------- Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import { WelcomeStep } from "@/features/onboarding/components/WelcomeStep";
|
||||
import { PrerequisitesStep } from "@/features/onboarding/components/PrerequisitesStep";
|
||||
import { ConnectStep } from "@/features/onboarding/components/ConnectStep";
|
||||
import { AgentsStep } from "@/features/onboarding/components/AgentsStep";
|
||||
import { CompanyStep } from "@/features/onboarding/components/CompanyStep";
|
||||
import { CompleteStep } from "@/features/onboarding/components/CompleteStep";
|
||||
|
||||
export type OnboardingWizardProps = {
|
||||
@@ -36,6 +37,12 @@ export type OnboardingWizardProps = {
|
||||
onConnect: () => void;
|
||||
/** Called when the user finishes or dismisses the wizard. */
|
||||
onComplete: () => void;
|
||||
/** Opens the reusable company builder. */
|
||||
onOpenCompanyBuilder: () => void;
|
||||
initialStep?: OnboardingStepId;
|
||||
initialCompletedSteps?: OnboardingStepId[];
|
||||
createdCompanyName?: string | null;
|
||||
companyCreated?: boolean;
|
||||
/** Connection error message, if any. */
|
||||
connectionError: string | null;
|
||||
/** Whether we're currently connecting. */
|
||||
@@ -51,12 +58,17 @@ export const OnboardingWizard = ({
|
||||
onTokenChange,
|
||||
onConnect,
|
||||
onComplete,
|
||||
onOpenCompanyBuilder,
|
||||
initialStep = "welcome",
|
||||
initialCompletedSteps,
|
||||
createdCompanyName = null,
|
||||
companyCreated = false,
|
||||
connectionError,
|
||||
connecting,
|
||||
}: OnboardingWizardProps) => {
|
||||
const [currentStep, setCurrentStep] = useState<OnboardingStepId>("welcome");
|
||||
const [currentStep, setCurrentStep] = useState<OnboardingStepId>(initialStep);
|
||||
const [completedSteps, setCompletedSteps] = useState<Set<OnboardingStepId>>(
|
||||
new Set(),
|
||||
() => new Set(initialCompletedSteps ?? []),
|
||||
);
|
||||
|
||||
const stepIndex = useMemo(() => getStepIndex(currentStep), [currentStep]);
|
||||
@@ -116,8 +128,21 @@ export const OnboardingWizard = ({
|
||||
);
|
||||
case "agents":
|
||||
return <AgentsStep agentCount={agentCount} connected={gatewayConnected} />;
|
||||
case "company":
|
||||
return (
|
||||
<CompanyStep
|
||||
connected={gatewayConnected}
|
||||
agentCount={agentCount}
|
||||
onOpenCompanyBuilder={onOpenCompanyBuilder}
|
||||
/>
|
||||
);
|
||||
case "complete":
|
||||
return <CompleteStep />;
|
||||
return (
|
||||
<CompleteStep
|
||||
companyCreated={companyCreated}
|
||||
companyName={createdCompanyName}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -125,7 +150,7 @@ export const OnboardingWizard = ({
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-[100000] flex items-center justify-center bg-black/70 backdrop-blur-sm">
|
||||
<div className="relative mx-4 flex w-full max-w-[560px] flex-col overflow-hidden rounded-xl border border-white/10 bg-[#0d1117] shadow-2xl">
|
||||
<div className="relative mx-4 flex h-[min(92vh,640px)] w-full max-w-[560px] flex-col overflow-hidden rounded-xl border border-white/10 bg-[#0d1117] shadow-2xl">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between border-b border-white/10 px-6 py-4">
|
||||
<div>
|
||||
@@ -154,9 +179,9 @@ export const OnboardingWizard = ({
|
||||
key={step.id}
|
||||
className={`h-1 flex-1 rounded-full transition-colors ${
|
||||
idx <= stepIndex
|
||||
? "bg-emerald-500"
|
||||
? "bg-amber-400"
|
||||
: completedSteps.has(step.id)
|
||||
? "bg-emerald-500/40"
|
||||
? "bg-amber-400/40"
|
||||
: "bg-white/10"
|
||||
}`}
|
||||
/>
|
||||
@@ -164,7 +189,7 @@ export const OnboardingWizard = ({
|
||||
</div>
|
||||
|
||||
{/* Step content */}
|
||||
<div className="min-h-[280px] px-6 py-5">{renderStepContent()}</div>
|
||||
<div className="min-h-0 flex-1 overflow-y-auto px-6 py-4">{renderStepContent()}</div>
|
||||
|
||||
{/* Footer navigation */}
|
||||
<div className="flex items-center justify-between border-t border-white/10 px-6 py-4">
|
||||
@@ -187,7 +212,7 @@ export const OnboardingWizard = ({
|
||||
{currentStep === "complete" ? (
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center gap-1.5 rounded-md bg-emerald-600 px-4 py-2 text-xs font-semibold text-white transition-colors hover:bg-emerald-500"
|
||||
className="inline-flex items-center gap-1.5 rounded-md bg-amber-500 px-4 py-2 text-xs font-semibold text-[#1a1206] transition-colors hover:bg-amber-400"
|
||||
onClick={onComplete}
|
||||
>
|
||||
Enter Office
|
||||
|
||||
Reference in New Issue
Block a user