import { useCallback, useEffect, useMemo, useState, type ComponentType } from "react"; import { AlertCircle, GitPullRequest, Key, Lightbulb, X, Zap } from "lucide-react"; import { fetchAuthStatus, fetchGlobalSettings } from "../api"; import { dismissPostOnboardingRecommendations, isOnboardingCompleted, isPostOnboardingDismissed, } from "./model-onboarding-state"; interface PostOnboardingRecommendationsProps { onOpenSettings: (section: string) => void; onOpenModelOnboarding: () => void; } interface RecommendationItem { id: "ai-provider" | "default-model" | "github"; title: string; description: string; actionLabel: string; onAction: () => void; icon: ComponentType<{ size?: number; className?: string; "aria-hidden"?: boolean }>; } export function PostOnboardingRecommendations({ onOpenSettings, onOpenModelOnboarding, }: PostOnboardingRecommendationsProps) { const onboardingCompleted = isOnboardingCompleted(); const postOnboardingDismissed = isPostOnboardingDismissed(); const [loading, setLoading] = useState(true); const [hasError, setHasError] = useState(false); const [dismissedLocally, setDismissedLocally] = useState(false); const [incompleteState, setIncompleteState] = useState<{ needsAiProvider: boolean; needsDefaultModel: boolean; needsGitHub: boolean; }>({ needsAiProvider: false, needsDefaultModel: false, needsGitHub: false, }); useEffect(() => { if (!onboardingCompleted || postOnboardingDismissed) { setLoading(false); return; } let cancelled = false; const load = async () => { try { setLoading(true); setHasError(false); const [authStatus, globalSettings] = await Promise.all([ fetchAuthStatus(), fetchGlobalSettings(), ]); if (cancelled) { return; } const providers = authStatus.providers ?? []; const githubProvider = providers.find((provider) => provider.id === "github"); const hasAuthenticatedAiProvider = providers.some( (provider) => provider.id !== "github" && provider.authenticated, ); const needsAiProvider = !hasAuthenticatedAiProvider; const needsDefaultModel = !globalSettings.defaultProvider && !globalSettings.defaultModelId; const needsGitHub = githubProvider ? !githubProvider.authenticated : false; setIncompleteState({ needsAiProvider, needsDefaultModel, needsGitHub }); } catch { if (!cancelled) { setHasError(true); } } finally { if (!cancelled) { setLoading(false); } } }; void load(); return () => { cancelled = true; }; }, [onboardingCompleted, postOnboardingDismissed]); const handleDismiss = useCallback(() => { dismissPostOnboardingRecommendations(); setDismissedLocally(true); }, []); const handleOpenModelOnboarding = useCallback(() => { onOpenModelOnboarding(); }, [onOpenModelOnboarding]); const handleOpenGlobalModels = useCallback(() => { onOpenSettings("global-models"); }, [onOpenSettings]); const handleOpenAuthentication = useCallback(() => { onOpenSettings("authentication"); }, [onOpenSettings]); const recommendations = useMemo(() => { const items: RecommendationItem[] = []; if (incompleteState.needsAiProvider) { items.push({ id: "ai-provider", title: "Connect AI Provider", description: "Connect an AI provider to enable AI agents for task planning and code generation", actionLabel: "Set Up AI", onAction: handleOpenModelOnboarding, icon: Zap, }); } if (incompleteState.needsDefaultModel) { items.push({ id: "default-model", title: "Select Default Model", description: "Choose a default AI model for task execution", actionLabel: "Choose Model", onAction: handleOpenGlobalModels, icon: Key, }); } if (incompleteState.needsGitHub) { items.push({ id: "github", title: "Connect GitHub", description: "Connect GitHub to import issues and track pull requests", actionLabel: "Connect GitHub", onAction: handleOpenAuthentication, icon: GitPullRequest, }); } return items; }, [ incompleteState.needsAiProvider, incompleteState.needsDefaultModel, incompleteState.needsGitHub, handleOpenAuthentication, handleOpenGlobalModels, handleOpenModelOnboarding, ]); if (!onboardingCompleted || postOnboardingDismissed || dismissedLocally || loading || hasError || recommendations.length === 0) { return null; } return (

Recommended Next Steps

Complete these setup items to get the most out of Fusion.

    {recommendations.map((item) => { const ItemIcon = item.icon; return (
  • {item.title} {item.description}
  • ); })}
); }