mirror of
https://github.com/BillyOutlast/posthog.git
synced 2026-02-04 03:01:23 +01:00
feat: new button for analyzing survey responses (#38472)
This commit is contained in:
@@ -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.',
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user