diff --git a/frontend/src/scenes/insights/views/LineGraph/LineGraph.tsx b/frontend/src/scenes/insights/views/LineGraph/LineGraph.tsx
index 34f683d268e75..2c01232be06d8 100644
--- a/frontend/src/scenes/insights/views/LineGraph/LineGraph.tsx
+++ b/frontend/src/scenes/insights/views/LineGraph/LineGraph.tsx
@@ -215,6 +215,7 @@ export interface LineGraphProps {
showValueOnSeries?: boolean | null
showPercentStackView?: boolean | null
supportsPercentStackView?: boolean
+ hideAnnotations?: boolean
}
export const LineGraph = (props: LineGraphProps): JSX.Element => {
@@ -245,6 +246,7 @@ export function LineGraph_({
showValueOnSeries,
showPercentStackView,
supportsPercentStackView,
+ hideAnnotations,
}: LineGraphProps): JSX.Element {
let datasets = _datasets
@@ -272,7 +274,7 @@ export function LineGraph_({
const isBar = [GraphType.Bar, GraphType.HorizontalBar, GraphType.Histogram].includes(type)
const isBackgroundBasedGraphType = [GraphType.Bar, GraphType.HorizontalBar].includes(type)
const isPercentStackView = !!supportsPercentStackView && !!showPercentStackView
- const showAnnotations = isTrends && !isHorizontal
+ const showAnnotations = isTrends && !isHorizontal && !hideAnnotations
const shouldAutoResize = isHorizontal && !inCardView
// Remove tooltip element on unmount
diff --git a/frontend/src/scenes/surveys/SurveyView.tsx b/frontend/src/scenes/surveys/SurveyView.tsx
index af4208913bb97..50df0d98113a2 100644
--- a/frontend/src/scenes/surveys/SurveyView.tsx
+++ b/frontend/src/scenes/surveys/SurveyView.tsx
@@ -30,7 +30,7 @@ import { dayjs } from 'lib/dayjs'
import { defaultSurveyAppearance, SURVEY_EVENT_NAME } from './constants'
import { FEATURE_FLAGS } from 'lib/constants'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
-import { Summary } from './surveyViewViz'
+import { RatingQuestionBarChart, Summary } from './surveyViewViz'
export function SurveyView({ id }: { id: string }): JSX.Element {
const { survey, surveyLoading, surveyPlugin, showSurveyAppWarning } = useValues(surveyLogic)
@@ -264,6 +264,8 @@ export function SurveyResult({ disableEventsTable }: { disableEventsTable?: bool
currentQuestionIndexAndType,
surveyUserStats,
surveyUserStatsLoading,
+ surveyRatingResults,
+ surveyRatingResultsReady,
} = useValues(surveyLogic)
const { setCurrentQuestionIndexAndType } = useActions(surveyLogic)
const { featureFlags } = useValues(featureFlagLogic)
@@ -271,9 +273,24 @@ export function SurveyResult({ disableEventsTable }: { disableEventsTable?: bool
return (
<>
{featureFlags[FEATURE_FLAGS.SURVEYS_RESULTS_VISUALIZATIONS] && (
-
+ <>
+
+ {survey.questions.map((question, i) => {
+ if (question.type === 'rating') {
+ return (
+
+ )
+ }
+ })}
+ >
)}
- {surveyMetricsQueries && (
+ {surveyMetricsQueries && !featureFlags[FEATURE_FLAGS.SURVEYS_RESULTS_VISUALIZATIONS] && (
@@ -283,7 +300,7 @@ export function SurveyResult({ disableEventsTable }: { disableEventsTable?: bool
)}
- {survey.questions.length > 1 && (
+ {survey.questions.length > 1 && !featureFlags[FEATURE_FLAGS.SURVEYS_RESULTS_VISUALIZATIONS] && (
)}
- {currentQuestionIndexAndType.type === SurveyQuestionType.Rating && (
-
-
- {featureFlags[FEATURE_FLAGS.SURVEY_NPS_RESULTS] &&
- (survey.questions[currentQuestionIndexAndType.idx] as RatingSurveyQuestion).scale === 10 && (
- <>
-
-
NPS Score
-
- >
- )}
-
- )}
+ {currentQuestionIndexAndType.type === SurveyQuestionType.Rating &&
+ !featureFlags[FEATURE_FLAGS.SURVEYS_RESULTS_VISUALIZATIONS] && (
+
+
+ {featureFlags[FEATURE_FLAGS.SURVEY_NPS_RESULTS] &&
+ (survey.questions[currentQuestionIndexAndType.idx] as RatingSurveyQuestion).scale ===
+ 10 && (
+ <>
+
+
NPS Score
+
+ >
+ )}
+
+ )}
{(currentQuestionIndexAndType.type === SurveyQuestionType.SingleChoice ||
currentQuestionIndexAndType.type === SurveyQuestionType.MultipleChoice) && (
diff --git a/frontend/src/scenes/surveys/surveyLogic.tsx b/frontend/src/scenes/surveys/surveyLogic.tsx
index 21a016c7eb3a3..c56ce8ab4cb9f 100644
--- a/frontend/src/scenes/surveys/surveyLogic.tsx
+++ b/frontend/src/scenes/surveys/surveyLogic.tsx
@@ -16,6 +16,7 @@ import {
SurveyQuestionType,
SurveyType,
SurveyUrlMatchType,
+ RatingSurveyQuestion,
} from '~/types'
import type { surveyLogicType } from './surveyLogicType'
import { DataTableNode, InsightVizNode, HogQLQuery, NodeKind } from '~/queries/schema'
@@ -51,6 +52,14 @@ export interface SurveyUserStats {
sent: number
}
+export interface SurveyRatingResults {
+ [key: string]: number[]
+}
+
+export interface SurveyRatingResultsReady {
+ [key: string]: boolean
+}
+
export const surveyLogic = kea
([
props({} as SurveyLogicProps),
key(({ id }) => id),
@@ -172,6 +181,46 @@ export const surveyLogic = kea([
}
},
},
+ surveyRatingResults: {
+ loadSurveyRatingResults: async ({
+ questionIndex,
+ question,
+ }: {
+ questionIndex: number
+ question: RatingSurveyQuestion
+ }): Promise<{ [key: string]: number[] }> => {
+ const { survey } = values
+ const startDate = dayjs((survey as Survey).created_at).format('YYYY-MM-DD')
+ const endDate = survey.end_date
+ ? dayjs(survey.end_date).add(1, 'day').format('YYYY-MM-DD')
+ : dayjs().add(1, 'day').format('YYYY-MM-DD')
+
+ const surveyResponseField =
+ questionIndex === 0 ? '$survey_response' : `$survey_response_${questionIndex}`
+
+ const query: HogQLQuery = {
+ kind: NodeKind.HogQLQuery,
+ query: `
+ SELECT properties.${surveyResponseField} AS survey_response, COUNT(survey_response)
+ FROM events
+ WHERE event = 'survey sent'
+ AND properties.$survey_id = '${props.id}'
+ AND timestamp >= '${startDate}'
+ AND timestamp <= '${endDate}'
+ GROUP BY survey_response
+ `,
+ }
+ const responseJSON = await api.query(query)
+ const { results } = responseJSON
+
+ const resultArr = new Array(question.scale).fill(0)
+ results?.forEach(([value, count]) => {
+ resultArr[value - 1] = count
+ })
+
+ return { ...values.surveyRatingResults, [`question_${questionIndex}`]: resultArr }
+ },
+ },
})),
listeners(({ actions }) => ({
createSurveySuccess: ({ survey }) => {
@@ -261,6 +310,14 @@ export const surveyLogic = kea([
setCurrentQuestionIndexAndType: (_, { idx, type }) => ({ idx, type }),
},
],
+ surveyRatingResultsReady: [
+ {},
+ {
+ loadSurveyRatingResultsSuccess: (state, { payload }) => {
+ return { ...state, [`question_${payload?.questionIndex}`]: true }
+ },
+ },
+ ],
writingHTMLDescription: [
false,
{
diff --git a/frontend/src/scenes/surveys/surveyViewViz.tsx b/frontend/src/scenes/surveys/surveyViewViz.tsx
index 4969dff248da4..460536bb35b6d 100644
--- a/frontend/src/scenes/surveys/surveyViewViz.tsx
+++ b/frontend/src/scenes/surveys/surveyViewViz.tsx
@@ -1,6 +1,16 @@
import { LemonTable } from '@posthog/lemon-ui'
-import { SurveyUserStats } from './surveyLogic'
+import { surveyLogic, SurveyRatingResults, SurveyRatingResultsReady, SurveyUserStats } from './surveyLogic'
+import { useActions, BindLogic } from 'kea'
import { Tooltip } from 'lib/lemon-ui/Tooltip'
+import { GraphType } from '~/types'
+import { LineGraph } from 'scenes/insights/views/LineGraph/LineGraph'
+import { insightLogic } from 'scenes/insights/insightLogic'
+import { InsightLogicProps, RatingSurveyQuestion } from '~/types'
+import { useEffect } from 'react'
+
+const insightProps: InsightLogicProps = {
+ dashboardItemId: `new-survey`,
+}
const formatCount = (count: number, total: number): string => {
if ((count / total) * 100 < 3) {
@@ -48,8 +58,8 @@ export function UsersStackedBar({ surveyUserStats }: { surveyUserStats: SurveyUs
{
count: seen,
label: 'Viewed',
- classes: `bg-primary rounded-l ${dismissed === 0 && sent === 0 ? 'rounded-r' : ''}`,
- style: { width: `${seenPercentage}%` },
+ classes: `rounded-l ${dismissed === 0 && sent === 0 ? 'rounded-r' : ''}`,
+ style: { backgroundColor: '#1D4AFF', width: `${seenPercentage}%` },
},
{
count: dismissed,
@@ -92,12 +102,12 @@ export function UsersStackedBar({ surveyUserStats }: { surveyUserStats: SurveyUs
{[
- { count: seen, label: 'Viewed', color: 'bg-primary' },
- { count: dismissed, label: 'Dismissed', color: 'bg-warning' },
- { count: sent, label: 'Submitted', color: 'bg-success' },
- ].map(({ count, label, color }) => (
+ { count: seen, label: 'Viewed', style: { backgroundColor: '#1D4AFF' } },
+ { count: dismissed, label: 'Dismissed', style: { backgroundColor: '#E3A506' } },
+ { count: sent, label: 'Submitted', style: { backgroundColor: '#529B08' } },
+ ].map(({ count, label, style }) => (
-
+
{`${label} (${(
(count / total) *
100
@@ -119,20 +129,86 @@ export function Summary({
surveyUserStats: SurveyUserStats
surveyUserStatsLoading: boolean
}): JSX.Element {
- if (!surveyUserStats) {
- return <>>
- }
-
return (
-
+
{surveyUserStatsLoading ? (
) : (
<>
-
-
+ {!surveyUserStats ? null : (
+ <>
+
+
+ >
+ )}
>
)}
)
}
+
+export function RatingQuestionBarChart({
+ questionIndex,
+ question,
+ surveyRatingResults,
+ surveyRatingResultsReady,
+}: {
+ questionIndex: number
+ question: RatingSurveyQuestion
+ surveyRatingResults: SurveyRatingResults
+ surveyRatingResultsReady: SurveyRatingResultsReady
+}): JSX.Element {
+ const { loadSurveyRatingResults } = useActions(surveyLogic)
+
+ useEffect(() => {
+ loadSurveyRatingResults({ questionIndex, question })
+ }, [question])
+
+ return (
+
+ {!surveyRatingResultsReady[`question_${questionIndex}`] ? (
+
+ ) : (
+
+
{`1-${question.scale} rating`}
+
{question.question}
+
+
+
+ (i + 1).toString()).map(
+ (n) => n
+ )}
+ />
+
+
+
+
+
{question.lowerBoundLabel}
+
{question.upperBoundLabel}
+
+
+ )}
+
+ )
+}