import React, { useCallback, useMemo, useState } from "react"; import { Check, ChevronDown } from "lucide-react"; import { useTranslation } from "react-i18next"; import SessionProviderLogo from "../../../llm-logo-provider/SessionProviderLogo"; import { CLAUDE_MODELS, CURSOR_MODELS, CODEX_MODELS, GEMINI_MODELS, } from "../../../../../shared/modelConstants"; import type { ProjectSession, LLMProvider } from "../../../../types/app"; import { NextTaskBanner } from "../../../task-master"; import { Dialog, DialogTrigger, DialogContent, DialogTitle, Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Card, } from "../../../../shared/view/ui"; type ProviderSelectionEmptyStateProps = { selectedSession: ProjectSession | null; currentSessionId: string | null; provider: LLMProvider; setProvider: (next: LLMProvider) => void; textareaRef: React.RefObject; claudeModel: string; setClaudeModel: (model: string) => void; cursorModel: string; setCursorModel: (model: string) => void; codexModel: string; setCodexModel: (model: string) => void; geminiModel: string; setGeminiModel: (model: string) => void; tasksEnabled: boolean; isTaskMasterInstalled: boolean | null; onShowAllTasks?: (() => void) | null; setInput: React.Dispatch>; }; interface ProviderGroup { id: LLMProvider; name: string; models: { value: string; label: string }[]; } const PROVIDER_GROUPS: ProviderGroup[] = [ { id: "claude", name: "Anthropic", models: CLAUDE_MODELS.OPTIONS }, { id: "cursor", name: "Cursor", models: CURSOR_MODELS.OPTIONS }, { id: "codex", name: "OpenAI", models: CODEX_MODELS.OPTIONS }, { id: "gemini", name: "Google", models: GEMINI_MODELS.OPTIONS }, ]; function getModelConfig(p: LLMProvider) { if (p === "claude") return CLAUDE_MODELS; if (p === "codex") return CODEX_MODELS; if (p === "gemini") return GEMINI_MODELS; return CURSOR_MODELS; } function getCurrentModel( p: LLMProvider, c: string, cu: string, co: string, g: string, ) { if (p === "claude") return c; if (p === "codex") return co; if (p === "gemini") return g; return cu; } function getProviderDisplayName(p: LLMProvider) { if (p === "claude") return "Claude"; if (p === "cursor") return "Cursor"; if (p === "codex") return "Codex"; return "Gemini"; } export default function ProviderSelectionEmptyState({ selectedSession, currentSessionId, provider, setProvider, textareaRef, claudeModel, setClaudeModel, cursorModel, setCursorModel, codexModel, setCodexModel, geminiModel, setGeminiModel, tasksEnabled, isTaskMasterInstalled, onShowAllTasks, setInput, }: ProviderSelectionEmptyStateProps) { const { t } = useTranslation("chat"); const [dialogOpen, setDialogOpen] = useState(false); const nextTaskPrompt = t("tasks.nextTaskPrompt", { defaultValue: "Start the next task", }); const currentModel = getCurrentModel( provider, claudeModel, cursorModel, codexModel, geminiModel, ); const currentModelLabel = useMemo(() => { const config = getModelConfig(provider); const found = config.OPTIONS.find( (o: { value: string; label: string }) => o.value === currentModel, ); return found?.label || currentModel; }, [provider, currentModel]); const handleModelSelect = useCallback( (providerId: LLMProvider, modelValue: string) => { // Set provider setProvider(providerId); localStorage.setItem("selected-provider", providerId); // Set model for the correct provider if (providerId === "claude") { setClaudeModel(modelValue); localStorage.setItem("claude-model", modelValue); } else if (providerId === "codex") { setCodexModel(modelValue); localStorage.setItem("codex-model", modelValue); } else if (providerId === "gemini") { setGeminiModel(modelValue); localStorage.setItem("gemini-model", modelValue); } else { setCursorModel(modelValue); localStorage.setItem("cursor-model", modelValue); } setDialogOpen(false); setTimeout(() => textareaRef.current?.focus(), 100); }, [setProvider, setClaudeModel, setCursorModel, setCodexModel, setGeminiModel, textareaRef], ); /* ── New session — provider + model picker ── */ if (!selectedSession && !currentSessionId) { return (
{/* Heading */}

{t("providerSelection.title")}

{t("providerSelection.description")}

{/* Model selector trigger — hero card style */}
{getProviderDisplayName(provider)} · {currentModelLabel}

{t("providerSelection.clickToChange", { defaultValue: "Click to change model", })}

Model Selector {t("providerSelection.noModelsFound", { defaultValue: "No models found." })} {PROVIDER_GROUPS.map((group) => ( {group.name} } > {group.models.map((model) => { const isSelected = provider === group.id && currentModel === model.value; return ( handleModelSelect(group.id, model.value)} > {model.label} {isSelected && ( )} ); })} ))}
{/* Ready prompt */}

{ { claude: t("providerSelection.readyPrompt.claude", { model: claudeModel, }), cursor: t("providerSelection.readyPrompt.cursor", { model: cursorModel, }), codex: t("providerSelection.readyPrompt.codex", { model: codexModel, }), gemini: t("providerSelection.readyPrompt.gemini", { model: geminiModel, }), }[provider] }

{/* Task banner */} {provider && tasksEnabled && isTaskMasterInstalled && (
setInput(nextTaskPrompt)} onShowAllTasks={onShowAllTasks} />
)}
); } /* ── Existing session — continue prompt ── */ if (selectedSession) { return (

{t("session.continue.title")}

{t("session.continue.description")}

{tasksEnabled && isTaskMasterInstalled && (
setInput(nextTaskPrompt)} onShowAllTasks={onShowAllTasks} />
)}
); } return null; }