feat: new button for analyzing survey responses (#38472)

This commit is contained in:
Lucas Faria
2025-09-23 10:00:31 -03:00
committed by GitHub
parent dae7d925c4
commit 3522443551
4 changed files with 72 additions and 37 deletions

View File

@@ -578,6 +578,9 @@ export const QUESTION_SUGGESTIONS_DATA: readonly SuggestionGroup[] = [
{
content: 'Create a survey to measure product market fit',
},
{
content: 'Analyze survey responses to prioritize key features our users are interested in',
},
],
url: urls.surveys(),
tooltip: 'Max can help you create surveys to collect feedback from your users.',

View File

@@ -1,7 +1,7 @@
import './SurveyView.scss'
import { useActions, useValues } from 'kea'
import { useEffect, useMemo, useState } from 'react'
import { useEffect, useState } from 'react'
import { IconGraph, IconTrash } from '@posthog/icons'
import { LemonButton, LemonDialog, LemonDivider } from '@posthog/lemon-ui'
@@ -15,7 +15,6 @@ import { LemonTabs } from 'lib/lemon-ui/LemonTabs'
import { ButtonPrimitive } from 'lib/ui/Button/ButtonPrimitives'
import { WrappingLoadingSkeleton } from 'lib/ui/WrappingLoadingSkeleton/WrappingLoadingSkeleton'
import { LinkedHogFunctions } from 'scenes/hog-functions/list/LinkedHogFunctions'
import { MaxTool } from 'scenes/max/MaxTool'
import { organizationLogic } from 'scenes/organizationLogic'
import { DuplicateToProjectModal } from 'scenes/surveys/DuplicateToProjectModal'
import { SurveyNoResponsesBanner } from 'scenes/surveys/SurveyNoResponsesBanner'
@@ -52,7 +51,6 @@ import {
import { SurveysDisabledBanner } from './SurveySettings'
const RESOURCE_TYPE = 'survey'
const NUM_OF_RESPONSES_FOR_MAX_ANALYSIS_TOOL = 10
export function SurveyView({ id }: { id: string }): JSX.Element {
const { survey, surveyLoading } = useValues(surveyLogic)
@@ -300,41 +298,22 @@ export function SurveyView({ id }: { id: string }): JSX.Element {
}
function SurveyResponsesByQuestionV2(): JSX.Element {
const { survey, isSurveyAnalysisMaxToolEnabled, formattedOpenEndedResponses } = useValues(surveyLogic)
const maxToolContext = useMemo(
() => ({
survey_id: survey.id,
survey_name: survey.name,
formatted_responses: formattedOpenEndedResponses,
}),
[survey.id, survey.name, formattedOpenEndedResponses]
)
const shouldShowMaxAnalysisTool = useMemo(() => {
if (!isSurveyAnalysisMaxToolEnabled) {
return false
}
const totalResponses = formattedOpenEndedResponses.reduce((acc, curr) => acc + curr.responses.length, 0)
return totalResponses >= NUM_OF_RESPONSES_FOR_MAX_ANALYSIS_TOOL
}, [isSurveyAnalysisMaxToolEnabled, formattedOpenEndedResponses])
const { survey } = useValues(surveyLogic)
return (
<MaxTool identifier="analyze_survey_responses" context={maxToolContext} active={shouldShowMaxAnalysisTool}>
<div className="flex flex-col gap-2">
{survey.questions.map((question, i) => {
if (!question.id || question.type === SurveyQuestionType.Link) {
return null
}
return (
<div key={question.id} className="flex flex-col gap-2">
<SurveyQuestionVisualization question={question} questionIndex={i} />
<LemonDivider />
</div>
)
})}
</div>
</MaxTool>
<div className="flex flex-col gap-2">
{survey.questions.map((question, i) => {
if (!question.id || question.type === SurveyQuestionType.Link) {
return null
}
return (
<div key={question.id} className="flex flex-col gap-2">
<SurveyQuestionVisualization question={question} questionIndex={i} />
<LemonDivider />
</div>
)
})}
</div>
)
}

View File

@@ -0,0 +1,50 @@
import { useValues } from 'kea'
import { useMemo } from 'react'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { useMaxTool } from 'scenes/max/useMaxTool'
import { surveyLogic } from 'scenes/surveys/surveyLogic'
const NUM_OF_RESPONSES_FOR_MAX_ANALYSIS_TOOL = 5
function useSurveyAnalysisMaxTool(): ReturnType<typeof useMaxTool> {
const { survey, isSurveyAnalysisMaxToolEnabled, formattedOpenEndedResponses } = useValues(surveyLogic)
const maxToolContext = useMemo(
() => ({
survey_id: survey.id,
survey_name: survey.name,
formatted_responses: formattedOpenEndedResponses,
}),
[survey.id, survey.name, formattedOpenEndedResponses]
)
const shouldShowMaxAnalysisTool = useMemo(() => {
if (!isSurveyAnalysisMaxToolEnabled) {
return false
}
const totalResponses = formattedOpenEndedResponses.reduce((acc, curr) => acc + curr.responses.length, 0)
return totalResponses >= NUM_OF_RESPONSES_FOR_MAX_ANALYSIS_TOOL
}, [isSurveyAnalysisMaxToolEnabled, formattedOpenEndedResponses])
return useMaxTool({
identifier: 'analyze_survey_responses',
context: maxToolContext,
active: shouldShowMaxAnalysisTool,
initialMaxPrompt: `Analyze the survey responses for the survey "${survey.name}"`,
})
}
export function AnalyzeResponsesButton(): JSX.Element | null {
const { openMax } = useSurveyAnalysisMaxTool()
if (!openMax) {
return null
}
return (
<LemonButton onClick={openMax} type="secondary">
Analyze responses
</LemonButton>
)
}

View File

@@ -5,6 +5,7 @@ import { LemonDivider, LemonSkeleton, Tooltip } from '@posthog/lemon-ui'
import { StatelessInsightLoadingState } from 'scenes/insights/EmptyStates'
import { SurveyNoResponsesBanner } from 'scenes/surveys/SurveyNoResponsesBanner'
import { AnalyzeResponsesButton } from 'scenes/surveys/components/AnalyzeResponsesButton'
import { MultipleChoiceQuestionViz } from 'scenes/surveys/components/question-visualizations/MultipleChoiceQuestionViz'
import { ResponseSummariesButton } from 'scenes/surveys/components/question-visualizations/OpenQuestionSummarizer'
import { OpenQuestionViz } from 'scenes/surveys/components/question-visualizations/OpenQuestionViz'
@@ -28,6 +29,7 @@ function QuestionTitle({
questionIndex,
totalResponses = 0,
}: Props & { totalResponses?: number }): JSX.Element {
const { isSurveyAnalysisMaxToolEnabled } = useValues(surveyLogic)
return (
<div className="flex flex-col">
<div className="inline-flex gap-1 max-w-fit font-semibold text-secondary items-center">
@@ -57,9 +59,10 @@ function QuestionTitle({
<h3 className="text-xl font-bold mb-0">
Question {questionIndex + 1}: {question.question}
</h3>
{question.type === SurveyQuestionType.Open && totalResponses > 5 && (
{question.type === SurveyQuestionType.Open && totalResponses > 5 && !isSurveyAnalysisMaxToolEnabled && (
<ResponseSummariesButton questionIndex={questionIndex} questionId={question.id} />
)}
{isSurveyAnalysisMaxToolEnabled && <AnalyzeResponsesButton />}
</div>
</div>
)