From d1a83dc11aeb1f541cd9b09e49297c21555bbe85 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Sat, 17 Jan 2026 18:22:00 -0800 Subject: [PATCH] fix: link out to google form for claude code in-product nudge --- .../src/components/survey/ClaudeCodeModal.tsx | 397 ++---------------- 1 file changed, 27 insertions(+), 370 deletions(-) diff --git a/ui/litellm-dashboard/src/components/survey/ClaudeCodeModal.tsx b/ui/litellm-dashboard/src/components/survey/ClaudeCodeModal.tsx index 1c0db00340f..94527c160c1 100644 --- a/ui/litellm-dashboard/src/components/survey/ClaudeCodeModal.tsx +++ b/ui/litellm-dashboard/src/components/survey/ClaudeCodeModal.tsx @@ -1,6 +1,6 @@ -import React, { useState } from "react"; -import { X, Code, ArrowRight, ArrowLeft } from "lucide-react"; -import { Button, Input, Radio, Space, Progress, Checkbox } from "antd"; +import React from "react"; +import { X, Code, ExternalLink } from "lucide-react"; +import { Button } from "antd"; interface ClaudeCodeModalProps { isOpen: boolean; @@ -8,359 +8,23 @@ interface ClaudeCodeModalProps { onComplete: () => void; } -const FEATURE_OPTIONS = [ - { - id: "model_compatibility", - label: "Model Compatibility", - description: "Works seamlessly with Claude models through LiteLLM", - }, - { - id: "performance", - label: "Performance & Speed", - description: "Fast response times and reliable connections", - }, - { - id: "debugging", - label: "Debugging & Observability", - description: "Easy to debug and monitor API calls", - }, - { - id: "cost_tracking", - label: "Cost Tracking", - description: "Helpful for tracking usage and costs", - }, - { - id: "other", - label: "Other", - description: "Something else not listed above", - }, -]; - -const IMPROVEMENT_OPTIONS = [ - { - id: "documentation", - label: "Documentation", - description: "Better guides for Claude Code integration", - }, - { - id: "error_messages", - label: "Error Messages", - description: "Clearer error messages and debugging info", - }, - { - id: "performance_optimization", - label: "Performance", - description: "Faster response times or lower latency", - }, - { - id: "additional_features", - label: "Additional Features", - description: "More features specific to Claude Code workflows", - }, - { - id: "nothing", - label: "Nothing - It's great!", - description: "I'm satisfied with the current experience", - }, - { - id: "other", - label: "Other", - description: "Something else not listed above", - }, -]; - -type SurveyData = { - satisfaction: string; - features: string[]; - improvements: string[]; - improvementOther: string; - email: string; -}; +const GOOGLE_FORM_URL = "https://forms.gle/LZeJQ3XytBakckYa9"; export function ClaudeCodeModal({ isOpen, onClose, onComplete }: ClaudeCodeModalProps) { - const [step, setStep] = useState(1); - const [data, setData] = useState({ - satisfaction: "", - features: [], - improvements: [], - improvementOther: "", - email: "", - }); - const [isSubmitting, setIsSubmitting] = useState(false); - - const totalSteps = 4; - if (!isOpen) return null; - const handleNext = () => { - if (step < 4) { - setStep(step + 1); - } else { - handleSubmit(); - } - }; - - const handleBack = () => { - setStep(step - 1); - }; - - const handleSubmit = async () => { - setIsSubmitting(true); - try { - // Map IDs to readable labels - const featureLabels: Record = { - model_compatibility: "Model Compatibility", - performance: "Performance & Speed", - debugging: "Debugging & Observability", - cost_tracking: "Cost Tracking", - }; - - const improvementLabels: Record = { - documentation: "Documentation", - error_messages: "Error Messages", - performance_optimization: "Performance", - additional_features: "Additional Features", - nothing: "Nothing - It's great!", - }; - - const readableFeatures = data.features.map((f) => { - if (f === "other") return "Other"; - return featureLabels[f] || f; - }); - - const readableImprovements = data.improvements.map((i) => { - if (i === "other" && data.improvementOther) { - return `Other: ${data.improvementOther}`; - } - return improvementLabels[i] || i; - }); - - await fetch("https://hooks.zapier.com/hooks/catch/16331268/ugms6w0/", { - method: "POST", - mode: "no-cors", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - surveyType: "Claude Code Feedback", - satisfaction: data.satisfaction, - features: readableFeatures.join(", "), - improvements: readableImprovements.join(", "), - improvementOther: data.improvementOther || null, - email: data.email || null, - submittedAt: new Date().toISOString(), - }), - }); - } catch (error) { - // Silently fail - don't block the user experience - console.error("Failed to submit Claude Code feedback:", error); - } - setIsSubmitting(false); + const handleOpenForm = () => { + window.open(GOOGLE_FORM_URL, "_blank", "noopener,noreferrer"); onComplete(); }; - const updateData = (key: keyof SurveyData, value: string | string[]) => { - setData((prev) => ({ - ...prev, - [key]: value, - })); - }; - - const toggleFeature = (featureId: string) => { - setData((prev) => ({ - ...prev, - features: prev.features.includes(featureId) - ? prev.features.filter((f) => f !== featureId) - : [...prev.features, featureId], - })); - }; - - const toggleImprovement = (improvementId: string) => { - setData((prev) => ({ - ...prev, - improvements: prev.improvements.includes(improvementId) - ? prev.improvements.filter((i) => i !== improvementId) - : [...prev.improvements, improvementId], - })); - }; - - const isStepValid = () => { - if (step === 1) return data.satisfaction !== ""; - if (step === 2) return data.features.length > 0; - if (step === 3) { - // If "other" is selected, require the text field - if (data.improvements.includes("other")) { - return data.improvements.length > 0 && data.improvementOther.trim().length > 0; - } - return data.improvements.length > 0; - } - if (step === 4) return true; // Email is optional - return false; - }; - - const renderStepContent = () => { - // Step 1: Satisfaction rating - if (step === 1) { - return ( -
-

How satisfied are you with using LiteLLM in Claude Code?

- updateData("satisfaction", e.target.value)} - className="w-full" - > - - {[ - "Very Satisfied", - "Satisfied", - "Neutral", - "Dissatisfied", - "Very Dissatisfied", - ].map((option) => ( - - ))} - - -
- ); - } - - // Step 2: What features do you value? - if (step === 2) { - return ( -
-

What do you value most about using LiteLLM with Claude Code?

-

Select all that apply.

-
- {FEATURE_OPTIONS.map((option) => { - const isSelected = data.features.includes(option.id); - return ( -
toggleFeature(option.id)} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - toggleFeature(option.id); - } - }} - className={`flex items-start p-4 rounded-lg border cursor-pointer transition-all ${ - isSelected - ? "border-purple-600 bg-purple-50 ring-1 ring-purple-600" - : "border-gray-200 hover:bg-gray-50" - }`} - > - -
- {option.label} - {option.description} -
-
- ); - })} -
-
- ); - } - - // Step 3: What could be improved? - if (step === 3) { - return ( -
-

What could we improve for Claude Code users?

-

Select all that apply.

-
- {IMPROVEMENT_OPTIONS.map((option) => { - const isSelected = data.improvements.includes(option.id); - return ( -
-
toggleImprovement(option.id)} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - toggleImprovement(option.id); - } - }} - className={`flex items-start p-4 rounded-lg border cursor-pointer transition-all ${ - isSelected - ? "border-purple-600 bg-purple-50 ring-1 ring-purple-600" - : "border-gray-200 hover:bg-gray-50" - }`} - > - -
- {option.label} - {option.description} -
-
- {/* Show text input if "Other" is selected */} - {option.id === "other" && isSelected && ( - updateData("improvementOther", e.target.value)} - onClick={(e) => e.stopPropagation()} - autoFocus - /> - )} -
- ); - })} -
-
- ); - } - - // Step 4: Email (optional) - if (step === 4) { - return ( -
-

Want to discuss further?

-

- Leave your email and we may reach out to learn more about your Claude Code experience. This is completely optional. -

- updateData("email", e.target.value)} - autoFocus - /> -

- We will only use this to follow up on your feedback. No spam, ever. -

-
- ); - } - - return null; - }; - - const isLastStep = step === 4; - return (
{/* Backdrop */}
{/* Modal */} -
+
{/* Header */}
@@ -375,35 +39,28 @@ export function ClaudeCodeModal({ isOpen, onClose, onComplete }: ClaudeCodeModal
- {/* Progress Bar */} - - {/* Content */} -
{renderStepContent()}
+
+

+ Help us improve your experience +

+

+ We'd love to hear about your experience using LiteLLM with Claude Code. Your feedback helps us improve the product for everyone. +

+

+ This brief survey takes about 2-3 minutes to complete. +

- {/* Footer */} -
-
- Step {step} of {totalSteps} -
-
- {step > 1 && ( - - )} - -
+