Skip to content

Commit c3da349

Browse files
fix: improve survey bundle size (#1759)
1 parent 48ae875 commit c3da349

File tree

5 files changed

+143
-173
lines changed

5 files changed

+143
-173
lines changed

src/__tests__/surveys.test.ts

+36-38
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// <reference lib="dom" />
22

33
import { SURVEYS_REQUEST_TIMEOUT_MS } from '../constants'
4-
import { generateSurveys } from '../extensions/surveys'
4+
import { generateSurveys, getNextSurveyStep } from '../extensions/surveys'
55
import {
66
canActivateRepeatedly,
77
getDisplayOrderChoices,
@@ -927,8 +927,8 @@ describe('surveys', () => {
927927
{ type: SurveyQuestionType.Open, question: 'Question A' },
928928
{ type: SurveyQuestionType.Open, question: 'Question B' },
929929
] as SurveyQuestion[]
930-
expect(surveys.getNextSurveyStep(survey, 0, 'Some response')).toEqual(1)
931-
expect(surveys.getNextSurveyStep(survey, 1, 'Some response')).toEqual(SurveyQuestionBranchingType.End)
930+
expect(getNextSurveyStep(survey, 0, 'Some response')).toEqual(1)
931+
expect(getNextSurveyStep(survey, 1, 'Some response')).toEqual(SurveyQuestionBranchingType.End)
932932
})
933933

934934
it('should branch out to `end`', () => {
@@ -940,7 +940,7 @@ describe('surveys', () => {
940940
},
941941
{ type: SurveyQuestionType.Open, question: 'Question B' },
942942
] as SurveyQuestion[]
943-
expect(surveys.getNextSurveyStep(survey, 0, 'Some response')).toEqual(SurveyQuestionBranchingType.End)
943+
expect(getNextSurveyStep(survey, 0, 'Some response')).toEqual(SurveyQuestionBranchingType.End)
944944
})
945945

946946
it('should branch out to a specific question', () => {
@@ -953,7 +953,7 @@ describe('surveys', () => {
953953
{ type: SurveyQuestionType.Open, question: 'Question B' },
954954
{ type: SurveyQuestionType.Open, question: 'Question C' },
955955
] as SurveyQuestion[]
956-
expect(surveys.getNextSurveyStep(survey, 0, 'Some response')).toEqual(2)
956+
expect(getNextSurveyStep(survey, 0, 'Some response')).toEqual(2)
957957
})
958958

959959
// Single-choice
@@ -973,9 +973,9 @@ describe('surveys', () => {
973973
{ type: SurveyQuestionType.Open, question: 'Why no?' },
974974
{ type: SurveyQuestionType.Open, question: 'Why maybe?' },
975975
] as unknown[] as SurveyQuestion[]
976-
expect(surveys.getNextSurveyStep(survey, 0, 'Yes')).toEqual(1)
977-
expect(surveys.getNextSurveyStep(survey, 0, 'No')).toEqual(2)
978-
expect(surveys.getNextSurveyStep(survey, 0, 'Maybe')).toEqual(3)
976+
expect(getNextSurveyStep(survey, 0, 'Yes')).toEqual(1)
977+
expect(getNextSurveyStep(survey, 0, 'No')).toEqual(2)
978+
expect(getNextSurveyStep(survey, 0, 'Maybe')).toEqual(3)
979979
})
980980

981981
// Response-based branching, scale 1-3
@@ -995,9 +995,9 @@ describe('surveys', () => {
995995
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
996996
] as unknown[] as SurveyQuestion[]
997997

998-
expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1)
999-
expect(surveys.getNextSurveyStep(survey, 0, 2)).toEqual(2)
1000-
expect(surveys.getNextSurveyStep(survey, 0, 3)).toEqual(3)
998+
expect(getNextSurveyStep(survey, 0, 1)).toEqual(1)
999+
expect(getNextSurveyStep(survey, 0, 2)).toEqual(2)
1000+
expect(getNextSurveyStep(survey, 0, 3)).toEqual(3)
10011001
})
10021002

10031003
// Response-based branching, scale 1-5
@@ -1017,9 +1017,9 @@ describe('surveys', () => {
10171017
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
10181018
] as unknown as SurveyQuestion[]
10191019

1020-
expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1)
1021-
expect(surveys.getNextSurveyStep(survey, 0, 3)).toEqual(2)
1022-
expect(surveys.getNextSurveyStep(survey, 0, 5)).toEqual(3)
1020+
expect(getNextSurveyStep(survey, 0, 1)).toEqual(1)
1021+
expect(getNextSurveyStep(survey, 0, 3)).toEqual(2)
1022+
expect(getNextSurveyStep(survey, 0, 5)).toEqual(3)
10231023
})
10241024

10251025
// Response-based branching, scale 1-7
@@ -1039,13 +1039,13 @@ describe('surveys', () => {
10391039
{ type: SurveyQuestionType.Open, question: 'Great! What did you enjoy the most?' },
10401040
] as unknown as SurveyQuestion[]
10411041

1042-
expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1)
1043-
expect(surveys.getNextSurveyStep(survey, 0, 2)).toEqual(1)
1044-
expect(surveys.getNextSurveyStep(survey, 0, 3)).toEqual(1)
1045-
expect(surveys.getNextSurveyStep(survey, 0, 4)).toEqual(2)
1046-
expect(surveys.getNextSurveyStep(survey, 0, 5)).toEqual(3)
1047-
expect(surveys.getNextSurveyStep(survey, 0, 6)).toEqual(3)
1048-
expect(surveys.getNextSurveyStep(survey, 0, 7)).toEqual(3)
1042+
expect(getNextSurveyStep(survey, 0, 1)).toEqual(1)
1043+
expect(getNextSurveyStep(survey, 0, 2)).toEqual(1)
1044+
expect(getNextSurveyStep(survey, 0, 3)).toEqual(1)
1045+
expect(getNextSurveyStep(survey, 0, 4)).toEqual(2)
1046+
expect(getNextSurveyStep(survey, 0, 5)).toEqual(3)
1047+
expect(getNextSurveyStep(survey, 0, 6)).toEqual(3)
1048+
expect(getNextSurveyStep(survey, 0, 7)).toEqual(3)
10491049
})
10501050

10511051
// Response-based branching, scale 0-10 (NPS)
@@ -1065,9 +1065,9 @@ describe('surveys', () => {
10651065
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
10661066
] as unknown as SurveyQuestion[]
10671067

1068-
expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1)
1069-
expect(surveys.getNextSurveyStep(survey, 0, 8)).toEqual(2)
1070-
expect(surveys.getNextSurveyStep(survey, 0, 10)).toEqual(3)
1068+
expect(getNextSurveyStep(survey, 0, 1)).toEqual(1)
1069+
expect(getNextSurveyStep(survey, 0, 8)).toEqual(2)
1070+
expect(getNextSurveyStep(survey, 0, 10)).toEqual(3)
10711071
})
10721072

10731073
it('should display questions in the order AGCEHDFB', () => {
@@ -1121,7 +1121,7 @@ describe('surveys', () => {
11211121
for (let i = 0; i < survey.questions.length; i++) {
11221122
const currentQuestion = survey.questions[currentStep]
11231123
actualOrder.push(currentQuestion.question)
1124-
currentStep = surveys.getNextSurveyStep(survey, currentStep, 'Some response')
1124+
currentStep = getNextSurveyStep(survey, currentStep, 'Some response')
11251125
}
11261126

11271127
expect(desiredOrder).toEqual(actualOrder)
@@ -1180,7 +1180,7 @@ describe('surveys', () => {
11801180
for (const answer of answers) {
11811181
const currentQuestion = survey.questions[currentStep]
11821182
actualOrder.push(currentQuestion.question)
1183-
currentStep = surveys.getNextSurveyStep(survey, currentStep, answer)
1183+
currentStep = getNextSurveyStep(survey, currentStep, answer)
11841184
}
11851185
expect(desiredOrder).toEqual(actualOrder)
11861186
expect(currentStep).toEqual(SurveyQuestionBranchingType.End)
@@ -1193,7 +1193,7 @@ describe('surveys', () => {
11931193
for (const answer of answers) {
11941194
const currentQuestion = survey.questions[currentStep]
11951195
actualOrder.push(currentQuestion.question)
1196-
currentStep = surveys.getNextSurveyStep(survey, currentStep, answer)
1196+
currentStep = getNextSurveyStep(survey, currentStep, answer)
11971197
}
11981198
expect(desiredOrder).toEqual(actualOrder)
11991199
expect(currentStep).toEqual(SurveyQuestionBranchingType.End)
@@ -1206,7 +1206,7 @@ describe('surveys', () => {
12061206
for (const answer of answers) {
12071207
const currentQuestion = survey.questions[currentStep]
12081208
actualOrder.push(currentQuestion.question)
1209-
currentStep = surveys.getNextSurveyStep(survey, currentStep, answer)
1209+
currentStep = getNextSurveyStep(survey, currentStep, answer)
12101210
}
12111211
expect(desiredOrder).toEqual(actualOrder)
12121212
expect(currentStep).toEqual(SurveyQuestionBranchingType.End)
@@ -1223,7 +1223,7 @@ describe('surveys', () => {
12231223
for (const answer of answers) {
12241224
const currentQuestion = survey.questions[currentStep]
12251225
actualOrder.push(currentQuestion.question)
1226-
currentStep = surveys.getNextSurveyStep(survey, currentStep, answer)
1226+
currentStep = getNextSurveyStep(survey, currentStep, answer)
12271227
}
12281228
expect(desiredOrder).toEqual(actualOrder)
12291229
expect(currentStep).toEqual(SurveyQuestionBranchingType.End)
@@ -1244,7 +1244,7 @@ describe('surveys', () => {
12441244
{ type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' },
12451245
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
12461246
] as unknown as SurveyQuestion[]
1247-
expect(() => surveys.getNextSurveyStep(survey, 0, 1)).toThrow('The scale must be one of: 3, 5, 7, 10')
1247+
expect(() => getNextSurveyStep(survey, 0, 1)).toThrow('The scale must be one of: 3, 5, 7, 10')
12481248
})
12491249

12501250
it('should throw an error for a response value out of the valid range', () => {
@@ -1262,13 +1262,13 @@ describe('surveys', () => {
12621262
{ type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' },
12631263
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
12641264
] as unknown as SurveyQuestion[]
1265-
expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-3')
1265+
expect(() => getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-3')
12661266
;(survey.questions[0] as RatingSurveyQuestion).scale = 5
1267-
expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-5')
1267+
expect(() => getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-5')
12681268
;(survey.questions[0] as RatingSurveyQuestion).scale = 7
1269-
expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-7')
1269+
expect(() => getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-7')
12701270
;(survey.questions[0] as RatingSurveyQuestion).scale = 10
1271-
expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 0-10')
1271+
expect(() => getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 0-10')
12721272
})
12731273

12741274
it('should throw an error for if a response value in a rating question is not an integer', () => {
@@ -1286,10 +1286,8 @@ describe('surveys', () => {
12861286
{ type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' },
12871287
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
12881288
] as unknown as SurveyQuestion[]
1289-
expect(() => surveys.getNextSurveyStep(survey, 0, '2')).toThrow('The response type must be an integer')
1290-
expect(() => surveys.getNextSurveyStep(survey, 0, 'some_string')).toThrow(
1291-
'The response type must be an integer'
1292-
)
1289+
expect(() => getNextSurveyStep(survey, 0, '2')).toThrow('The response type must be an integer')
1290+
expect(() => getNextSurveyStep(survey, 0, 'some_string')).toThrow('The response type must be an integer')
12931291
})
12941292
})
12951293

src/entrypoints/surveys-preview.es.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export { renderFeedbackWidgetPreview, renderSurveysPreview } from '../extensions/surveys'
2-
export { getNextSurveyStep } from '../posthog-surveys'
1+
export { getNextSurveyStep, renderFeedbackWidgetPreview, renderSurveysPreview } from '../extensions/surveys'

src/extensions/surveys.tsx

+104-12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,109 @@ const logger = createLogger('[Surveys]')
4444
const window = _window as Window & typeof globalThis
4545
const document = _document as Document
4646

47+
function getRatingBucketForResponseValue(responseValue: number, scale: number) {
48+
if (scale === 3) {
49+
if (responseValue < 1 || responseValue > 3) {
50+
throw new Error('The response must be in range 1-3')
51+
}
52+
53+
return responseValue === 1 ? 'negative' : responseValue === 2 ? 'neutral' : 'positive'
54+
} else if (scale === 5) {
55+
if (responseValue < 1 || responseValue > 5) {
56+
throw new Error('The response must be in range 1-5')
57+
}
58+
59+
return responseValue <= 2 ? 'negative' : responseValue === 3 ? 'neutral' : 'positive'
60+
} else if (scale === 7) {
61+
if (responseValue < 1 || responseValue > 7) {
62+
throw new Error('The response must be in range 1-7')
63+
}
64+
65+
return responseValue <= 3 ? 'negative' : responseValue === 4 ? 'neutral' : 'positive'
66+
} else if (scale === 10) {
67+
if (responseValue < 0 || responseValue > 10) {
68+
throw new Error('The response must be in range 0-10')
69+
}
70+
71+
return responseValue <= 6 ? 'detractors' : responseValue <= 8 ? 'passives' : 'promoters'
72+
}
73+
74+
throw new Error('The scale must be one of: 3, 5, 7, 10')
75+
}
76+
77+
export function getNextSurveyStep(
78+
survey: Survey,
79+
currentQuestionIndex: number,
80+
response: string | string[] | number | null
81+
) {
82+
const question = survey.questions[currentQuestionIndex]
83+
const nextQuestionIndex = currentQuestionIndex + 1
84+
85+
if (!question.branching?.type) {
86+
if (currentQuestionIndex === survey.questions.length - 1) {
87+
return SurveyQuestionBranchingType.End
88+
}
89+
90+
return nextQuestionIndex
91+
}
92+
93+
if (question.branching.type === SurveyQuestionBranchingType.End) {
94+
return SurveyQuestionBranchingType.End
95+
} else if (question.branching.type === SurveyQuestionBranchingType.SpecificQuestion) {
96+
if (Number.isInteger(question.branching.index)) {
97+
return question.branching.index
98+
}
99+
} else if (question.branching.type === SurveyQuestionBranchingType.ResponseBased) {
100+
// Single choice
101+
if (question.type === SurveyQuestionType.SingleChoice) {
102+
// :KLUDGE: for now, look up the choiceIndex based on the response
103+
// TODO: once QuestionTypes.MultipleChoiceQuestion is refactored, pass the selected choiceIndex into this method
104+
const selectedChoiceIndex = question.choices.indexOf(`${response}`)
105+
106+
if (question.branching?.responseValues?.hasOwnProperty(selectedChoiceIndex)) {
107+
const nextStep = question.branching.responseValues[selectedChoiceIndex]
108+
109+
// Specific question
110+
if (Number.isInteger(nextStep)) {
111+
return nextStep
112+
}
113+
114+
if (nextStep === SurveyQuestionBranchingType.End) {
115+
return SurveyQuestionBranchingType.End
116+
}
117+
118+
return nextQuestionIndex
119+
}
120+
} else if (question.type === SurveyQuestionType.Rating) {
121+
if (typeof response !== 'number' || !Number.isInteger(response)) {
122+
throw new Error('The response type must be an integer')
123+
}
124+
125+
const ratingBucket = getRatingBucketForResponseValue(response, question.scale)
126+
127+
if (question.branching?.responseValues?.hasOwnProperty(ratingBucket)) {
128+
const nextStep = question.branching.responseValues[ratingBucket]
129+
130+
// Specific question
131+
if (Number.isInteger(nextStep)) {
132+
return nextStep
133+
}
134+
135+
if (nextStep === SurveyQuestionBranchingType.End) {
136+
return SurveyQuestionBranchingType.End
137+
}
138+
139+
return nextQuestionIndex
140+
}
141+
}
142+
143+
return nextQuestionIndex
144+
}
145+
146+
logger.warn('Falling back to next question index due to unexpected branching type')
147+
return nextQuestionIndex
148+
}
149+
47150
export class SurveyManager {
48151
private posthog: PostHog
49152
private surveyInFocus: string | null
@@ -663,18 +766,7 @@ export function Questions({
663766

664767
setQuestionsResponses({ ...questionsResponses, [responseKey]: res })
665768

666-
// Old SDK, no branching
667-
if (!posthog.getNextSurveyStep) {
668-
const isLastDisplayedQuestion = displayQuestionIndex === survey.questions.length - 1
669-
if (isLastDisplayedQuestion) {
670-
sendSurveyEvent({ ...questionsResponses, [responseKey]: res }, survey, posthog)
671-
} else {
672-
setCurrentQuestionIndex(displayQuestionIndex + 1)
673-
}
674-
return
675-
}
676-
677-
const nextStep = posthog.getNextSurveyStep(survey, displayQuestionIndex, res)
769+
const nextStep = getNextSurveyStep(survey, displayQuestionIndex, res)
678770
if (nextStep === SurveyQuestionBranchingType.End) {
679771
sendSurveyEvent({ ...questionsResponses, [responseKey]: res }, survey, posthog)
680772
} else {

src/posthog-core.ts

+1-10
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { PostHogExceptions } from './posthog-exceptions'
2525
import { PostHogFeatureFlags } from './posthog-featureflags'
2626
import { PostHogPersistence } from './posthog-persistence'
2727
import { PostHogSurveys } from './posthog-surveys'
28-
import { Survey, SurveyCallback, SurveyQuestionBranchingType } from './posthog-surveys-types'
28+
import { SurveyCallback } from './posthog-surveys-types'
2929
import { RateLimiter } from './rate-limiter'
3030
import { RemoteConfigLoader } from './remote-config'
3131
import { extendURLParams, request, SUPPORTS_REQUEST } from './request'
@@ -1343,15 +1343,6 @@ export class PostHog {
13431343
this.surveys.canRenderSurvey(surveyId)
13441344
}
13451345

1346-
/** Get the next step of the survey: a question index or `end` */
1347-
getNextSurveyStep(
1348-
survey: Survey,
1349-
currentQuestionIndex: number,
1350-
response: string | string[] | number | null
1351-
): number | SurveyQuestionBranchingType.End {
1352-
return this.surveys.getNextSurveyStep(survey, currentQuestionIndex, response)
1353-
}
1354-
13551346
/**
13561347
* Identify a user with a unique ID instead of a PostHog
13571348
* randomly generated distinct_id. If the method is never called,

0 commit comments

Comments
 (0)