diff --git a/cypress/e2e/surveys.cy.ts b/cypress/e2e/surveys.cy.ts index 171be2076..0ece8acf0 100644 --- a/cypress/e2e/surveys.cy.ts +++ b/cypress/e2e/surveys.cy.ts @@ -738,6 +738,39 @@ describe('Surveys', () => { }) }) + it('captures survey sent event with iteration', () => { + cy.visit('./playground/cypress') + cy.intercept('GET', '**/surveys/*', { + surveys: [ + { + id: '123', + name: 'Test survey', + description: 'description', + type: 'popover', + start_date: '2021-01-01T00:00:00Z', + questions: [openTextQuestion], + current_iteration: 2, + current_iteration_start_date: '12-12-2004', + }, + ], + }).as('surveys') + cy.intercept('POST', '**/e/*').as('capture-assertion') + onPageLoad() + cy.get('.PostHogSurvey123').shadow().find('textarea').type('experiments is awesome!') + cy.get('.PostHogSurvey123').shadow().find('.form-submit').click() + cy.wait('@capture-assertion') + cy.wait('@capture-assertion').then(async ({ request }) => { + const captures = await getPayload(request) + expect(captures.map(({ event }) => event)).to.deep.equal(['survey shown', 'survey sent']) + expect(captures[1].properties).to.contain({ + $survey_id: '123', + $survey_response: 'experiments is awesome!', + $survey_iteration: 2, + $survey_iteration_start_date: '12-12-2004', + }) + }) + }) + it('captures survey shown event', () => { cy.visit('./playground/cypress') cy.intercept('GET', '**/surveys/*', { @@ -761,6 +794,36 @@ describe('Surveys', () => { }) }) + it('captures survey shown event with iteration', () => { + cy.visit('./playground/cypress') + cy.intercept('GET', '**/surveys/*', { + surveys: [ + { + id: '123', + name: 'Test survey', + description: 'description', + type: 'popover', + start_date: '2021-01-01T00:00:00Z', + questions: [openTextQuestion], + current_iteration: 2, + current_iteration_start_date: '12-12-2004', + }, + ], + }).as('surveys') + cy.intercept('POST', '**/e/*').as('capture-assertion') + onPageLoad() + cy.wait('@capture-assertion') + cy.wait('@capture-assertion').then(async ({ request }) => { + const captures = await getPayload(request) + expect(captures[0].event).to.equal('survey shown') + expect(captures[0].properties).to.contain({ + $survey_id: '123', + $survey_iteration: 2, + $survey_iteration_start_date: '12-12-2004', + }) + }) + }) + it('captures survey dismissed event', () => { cy.visit('./playground/cypress') cy.intercept('GET', '**/surveys/*', { @@ -784,5 +847,37 @@ describe('Surveys', () => { expect(captures.map(({ event }) => event)).to.contain('survey dismissed') }) }) + + it('captures survey dismissed event with iteration', () => { + cy.visit('./playground/cypress') + cy.intercept('GET', '**/surveys/*', { + surveys: [ + { + id: '123', + name: 'Test survey', + description: 'description', + type: 'popover', + start_date: '2021-01-01T00:00:00Z', + questions: [openTextQuestion], + current_iteration: 2, + current_iteration_start_date: '12-12-2004', + }, + ], + }).as('surveys') + cy.intercept('POST', '**/e/*').as('capture-assertion') + onPageLoad() + cy.get('.PostHogSurvey123').shadow().find('.cancel-btn-wrapper').click() + cy.wait('@capture-assertion') + cy.wait('@capture-assertion').then(async ({ request }) => { + const captures = await getPayload(request) + const dismissedEvent = captures.filter(({ event }) => event == 'survey dismissed')[0] + expect(dismissedEvent).to.not.be.null + expect(dismissedEvent.properties).to.contain({ + $survey_id: '123', + $survey_iteration: 2, + $survey_iteration_start_date: '12-12-2004', + }) + }) + }) }) }) diff --git a/src/extensions/surveys.tsx b/src/extensions/surveys.tsx index d6e13c27c..c4dcd37ce 100644 --- a/src/extensions/surveys.tsx +++ b/src/extensions/surveys.tsx @@ -6,10 +6,12 @@ import { style, defaultSurveyAppearance, sendSurveyEvent, + dismissedSurveyEvent, createShadow, getContrastingTextColor, SurveyContext, getDisplayOrderQuestions, + getSurveySeenKey, } from './surveys/surveys-utils' import * as Preact from 'preact' import { createWidgetShadow, createWidgetStyle } from './surveys-widget' @@ -96,7 +98,7 @@ export const callSurveys = (posthog: PostHog, forceReload: boolean = false) => { } } - if (!localStorage.getItem(`seenSurvey_${survey.id}`)) { + if (!localStorage.getItem(getSurveySeenKey(survey))) { const shadow = createShadow(style(survey?.appearance), survey.id) Preact.render(, shadow) } @@ -221,6 +223,8 @@ export function SurveyPopup({ posthog.capture('survey shown', { $survey_name: survey.name, $survey_id: survey.id, + $survey_iteration: survey.current_iteration, + $survey_iteration_start_date: survey.current_iteration_start_date, sessionRecordingUrl: posthog.get_session_replay_url?.(), }) localStorage.setItem(`lastSeenSurveyDate`, new Date().toISOString()) @@ -248,7 +252,7 @@ export function SurveyPopup({ value={{ isPreviewMode, previewPageIndex: previewPageIndex, - handleCloseSurveyPopup: () => closeSurveyPopup(survey, posthog, isPreviewMode), + handleCloseSurveyPopup: () => dismissedSurveyEvent(survey, posthog, isPreviewMode), }} > {!shouldShowConfirmation ? ( @@ -403,23 +407,6 @@ export function Questions({ ) } -const closeSurveyPopup = (survey: Survey, posthog?: PostHog, isPreviewMode?: boolean) => { - if (isPreviewMode || !posthog) { - return - } - - posthog.capture('survey dismissed', { - $survey_name: survey.name, - $survey_id: survey.id, - sessionRecordingUrl: posthog.get_session_replay_url?.(), - $set: { - [`$survey_dismissed/${survey.id}`]: true, - }, - }) - localStorage.setItem(`seenSurvey_${survey.id}`, 'true') - window.dispatchEvent(new Event('PHSurveyClosed')) -} - export function FeedbackWidget({ survey, forceDisableHtml, diff --git a/src/extensions/surveys/surveys-utils.tsx b/src/extensions/surveys/surveys-utils.tsx index 8a2b7684c..488eab8f8 100644 --- a/src/extensions/surveys/surveys-utils.tsx +++ b/src/extensions/surveys/surveys-utils.tsx @@ -537,21 +537,42 @@ export const sendSurveyEvent = ( posthog?: PostHog ) => { if (!posthog) return + localStorage.setItem(getSurveySeenKey(survey), 'true') - localStorage.setItem(`seenSurvey_${survey.id}`, 'true') posthog.capture('survey sent', { $survey_name: survey.name, $survey_id: survey.id, + $survey_iteration: survey.current_iteration, + $survey_iteration_start_date: survey.current_iteration_start_date, $survey_questions: survey.questions.map((question) => question.question), sessionRecordingUrl: posthog.get_session_replay_url?.(), ...responses, $set: { - [`$survey_responded/${survey.id}`]: true, + [getSurveyInteractionProperty(survey, 'responded')]: true, }, }) window.dispatchEvent(new Event('PHSurveySent')) } +export const dismissedSurveyEvent = (survey: Survey, posthog?: PostHog, readOnly?: boolean) => { + // TODO: state management and unit tests for this would be nice + if (readOnly || !posthog) { + return + } + posthog.capture('survey dismissed', { + $survey_name: survey.name, + $survey_id: survey.id, + $survey_iteration: survey.current_iteration, + $survey_iteration_start_date: survey.current_iteration_start_date, + sessionRecordingUrl: posthog.get_session_replay_url?.(), + $set: { + [getSurveyInteractionProperty(survey, 'dismissed')]: true, + }, + }) + localStorage.setItem(getSurveySeenKey(survey), 'true') + window.dispatchEvent(new Event('PHSurveyClosed')) +} + // Use the Fisher-yates algorithm to shuffle this array // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle export const shuffle = (array: any[]) => { @@ -604,6 +625,24 @@ export const getDisplayOrderQuestions = (survey: Survey): SurveyQuestion[] => { return reverseIfUnshuffled(survey.questions, shuffle(survey.questions)) } +export const getSurveySeenKey = (survey: Survey): string => { + let surveySeenKey = `seenSurvey_${survey.id}` + if (survey.current_iteration && survey.current_iteration > 0) { + surveySeenKey = `seenSurvey_${survey.id}_${survey.current_iteration}` + } + + return surveySeenKey +} + +const getSurveyInteractionProperty = (survey: Survey, action: string): string => { + let surveyProperty = `$survey_${action}/${survey.id}` + if (survey.current_iteration && survey.current_iteration > 0) { + surveyProperty = `$survey_${action}/${survey.id}/${survey.current_iteration}` + } + + return surveyProperty +} + export const SurveyContext = createContext<{ isPreviewMode: boolean previewPageIndex: number | undefined diff --git a/src/posthog-surveys-types.ts b/src/posthog-surveys-types.ts index 00497c8d7..f7247b12a 100644 --- a/src/posthog-surveys-types.ts +++ b/src/posthog-surveys-types.ts @@ -119,4 +119,6 @@ export interface Survey { } | null start_date: string | null end_date: string | null + current_iteration: number | null + current_iteration_start_date: string | null }