diff --git a/cypress/e2e/surveys.cy.ts b/cypress/e2e/surveys.cy.ts
index a086fd26b..b17ddd5bb 100644
--- a/cypress/e2e/surveys.cy.ts
+++ b/cypress/e2e/surveys.cy.ts
@@ -525,7 +525,7 @@ describe('Surveys', () => {
type: 'popover',
start_date: '2021-01-01T00:00:00Z',
questions: [emojiRatingQuestion],
- appearance: appearanceWithThanks,
+ appearance: { ...appearanceWithThanks, backgroundColor: 'black' },
},
],
}).as('surveys')
diff --git a/src/__tests__/extensions/surveys.test.ts b/src/__tests__/extensions/surveys.test.ts
index 9953f266f..d455bf588 100644
--- a/src/__tests__/extensions/surveys.test.ts
+++ b/src/__tests__/extensions/surveys.test.ts
@@ -1,5 +1,6 @@
import 'regenerator-runtime/runtime'
-import { createShadow, generateSurveys } from '../../extensions/surveys'
+import { generateSurveys } from '../../extensions/surveys'
+import { createShadow } from '../../extensions/surveys/surveys-utils'
import { SurveyType } from '../../posthog-surveys-types'
describe('survey display logic', () => {
diff --git a/src/extensions/surveys.tsx b/src/extensions/surveys.tsx
index 86a104877..b349548fe 100644
--- a/src/extensions/surveys.tsx
+++ b/src/extensions/surveys.tsx
@@ -12,42 +12,24 @@ import {
} from '../posthog-surveys-types'
import { window as _window, document as _document } from '../utils/globals'
-import { style, defaultSurveyAppearance, sendSurveyEvent } from './surveys/surveys-utils'
+import { style, defaultSurveyAppearance, sendSurveyEvent, createShadow } from './surveys/surveys-utils'
import { useContrastingTextColor } from './surveys/hooks/useContrastingTextColor'
import * as Preact from 'preact'
import { createWidgetShadow } from './surveys-widget'
import { useState, useEffect, useRef } from 'preact/hooks'
-import { _isArray, _isNull, _isNumber } from '../utils/type-utils'
-import { BottomSection } from './surveys/components/BottomSection'
+import { _isNumber } from '../utils/type-utils'
+import { ConfirmationMessage } from './surveys/components/ConfirmationMessage'
import {
- IconPosthogLogo,
- cancelSVG,
- checkSVG,
- dissatisfiedEmoji,
- neutralEmoji,
- satisfiedEmoji,
- veryDissatisfiedEmoji,
- verySatisfiedEmoji,
-} from './surveys/icons'
+ OpenTextQuestion,
+ LinkQuestion,
+ RatingQuestion,
+ MultipleChoiceQuestion,
+} from './surveys/components/QuestionTypes'
// We cast the types here which is dangerous but protected by the top level generateSurveys call
const window = _window as Window & typeof globalThis
const document = _document as Document
-export const createShadow = (styleSheet: string, surveyId: string) => {
- const div = document.createElement('div')
- div.className = `PostHogSurvey${surveyId}`
- const shadow = div.attachShadow({ mode: 'open' })
- if (styleSheet) {
- const styleElement = Object.assign(document.createElement('style'), {
- innerText: styleSheet,
- })
- shadow.appendChild(styleElement)
- }
- document.body.appendChild(div)
- return shadow
-}
-
const handleWidget = (posthog: PostHog, survey: Survey) => {
const shadow = createWidgetShadow(survey)
const surveyStyleSheet = style(survey.appearance)
@@ -131,52 +113,6 @@ export function generateSurveys(posthog: PostHog) {
}, 3000)
}
-const defaultBackgroundColor = '#eeeded'
-
-export function QuestionHeader({
- question,
- description,
- backgroundColor,
-}: {
- question: string
- description?: string | null
- backgroundColor?: string
-}) {
- return (
-
-
{question}
- {description &&
}
-
- )
-}
-
-export function Cancel({ onClick }: { onClick: () => void }) {
- return (
-
-
-
- )
-}
-
-export function PostHogLogo({ backgroundColor }: { backgroundColor?: string }) {
- const { textColor, ref } = useContrastingTextColor({ appearance: { backgroundColor } })
-
- return (
- }
- style={{ backgroundColor: backgroundColor, color: textColor }}
- className="footer-branding"
- >
- Survey by {IconPosthogLogo}
-
- )
-}
-
export function Surveys({ posthog, survey, style }: { posthog: PostHog; survey: Survey; style?: React.CSSProperties }) {
const [displayState, setDisplayState] = useState<'survey' | 'confirmation' | 'closed'>('survey')
@@ -224,6 +160,61 @@ export function Surveys({ posthog, survey, style }: { posthog: PostHog; survey:
)
}
+const questionTypeMap = (
+ question: SurveyQuestion,
+ questionIndex: number,
+ appearance: SurveyAppearance,
+ onSubmit: (res: string | string[] | number | null) => void,
+ closeSurveyPopup: () => void
+): JSX.Element => {
+ const mapping = {
+ [SurveyQuestionType.Open]: (
+
+ ),
+ [SurveyQuestionType.Link]: (
+
+ ),
+ [SurveyQuestionType.Rating]: (
+
+ ),
+ [SurveyQuestionType.SingleChoice]: (
+
+ ),
+ [SurveyQuestionType.MultipleChoice]: (
+
+ ),
+ }
+ return mapping[question.type]
+}
+
export function Questions({
survey,
posthog,
@@ -300,347 +291,6 @@ const closeSurveyPopup = (posthog: PostHog, survey: Survey) => {
window.dispatchEvent(new Event('PHSurveyClosed'))
}
-export function OpenTextQuestion({
- question,
- appearance,
- onSubmit,
- closeSurveyPopup,
-}: {
- question: BasicSurveyQuestion
- appearance: SurveyAppearance
- onSubmit: (text: string) => void
- closeSurveyPopup: () => void
-}) {
- const textRef = useRef(null)
- const [text, setText] = useState('')
-
- return (
-
- closeSurveyPopup()} />
-
-
- )
-}
-
-export function LinkQuestion({
- question,
- appearance,
- onSubmit,
- closeSurveyPopup,
-}: {
- question: LinkSurveyQuestion
- appearance: SurveyAppearance
- onSubmit: (clicked: string) => void
- closeSurveyPopup: () => void
-}) {
- return (
-
- closeSurveyPopup()} />
-
- onSubmit('link clicked')}
- />
-
- )
-}
-
-export function RatingQuestion({
- question,
- questionIndex,
- appearance,
- onSubmit,
- closeSurveyPopup,
-}: {
- question: RatingSurveyQuestion
- questionIndex: number
- appearance: SurveyAppearance
- onSubmit: (rating: number | null) => void
- closeSurveyPopup: () => void
-}) {
- const scale = question.scale
- const starting = question.scale === 10 ? 0 : 1
- const [rating, setRating] = useState(null)
-
- return (
-
-
closeSurveyPopup()} />
-
-
-
- {question.display === 'emoji' && (
-
- {(question.scale === 3 ? threeScaleEmojis : fiveScaleEmojis).map((emoji, idx) => {
- const active = idx + 1 === rating
- return (
-
- )
- })}
-
- )}
- {question.display === 'number' && (
-
- {(question.scale === 5 ? fiveScaleNumbers : tenScaleNumbers).map((number, idx) => {
- const active = rating === number
- return (
- {
- setRating(num)
- }}
- />
- )
- })}
-
- )}
-
-
-
{question.lowerBoundLabel}
-
{question.upperBoundLabel}
-
-
- onSubmit(rating)}
- />
-
- )
-}
-
-export function RatingButton({
- num,
- active,
- questionIndex,
- appearance,
- setActiveNumber,
-}: {
- num: number
- active: boolean
- questionIndex: number
- appearance: any
- setActiveNumber: (num: number) => void
-}) {
- const { textColor, ref } = useContrastingTextColor({ appearance, defaultTextColor: 'black' })
-
- return (
-
- )
-}
-
-export function ConfirmationMessage({
- confirmationHeader,
- confirmationDescription,
- appearance,
- onClose,
- styleOverrides,
-}: {
- confirmationHeader: string
- confirmationDescription: string
- appearance: SurveyAppearance
- onClose: () => void
- styleOverrides?: React.CSSProperties
-}) {
- return (
- <>
-
-
-
onClose()} />
- {confirmationHeader}
- {confirmationDescription && (
-
- )}
- onClose()}
- />
-
-
- >
- )
-}
-
-export function MultipleChoiceQuestion({
- question,
- questionIndex,
- appearance,
- onSubmit,
- closeSurveyPopup,
-}: {
- question: MultipleSurveyQuestion
- questionIndex: number
- appearance: SurveyAppearance
- onSubmit: (choices: string | string[] | null) => void
- closeSurveyPopup: () => void
-}) {
- const textRef = useRef(null)
- const [selectedChoices, setSelectedChoices] = useState(
- question.type === SurveyQuestionType.MultipleChoice ? [] : null
- )
- const [openChoiceSelected, setOpenChoiceSelected] = useState(false)
- const [openEndedInput, setOpenEndedInput] = useState('')
-
- const inputType = question.type === SurveyQuestionType.SingleChoice ? 'radio' : 'checkbox'
- return (
-
-
closeSurveyPopup()} />
-
-
- {
- if (openChoiceSelected && question.type === SurveyQuestionType.MultipleChoice) {
- if (_isArray(selectedChoices)) {
- onSubmit([...selectedChoices, openEndedInput])
- }
- } else {
- onSubmit(selectedChoices)
- }
- }}
- />
-
- )
-}
-
export function FeedbackWidget({ posthog, survey }: { posthog: PostHog; survey: Survey }): JSX.Element {
const [showSurvey, setShowSurvey] = useState(false)
const [styleOverrides, setStyle] = useState({})
@@ -681,63 +331,3 @@ export function FeedbackWidget({ posthog, survey }: { posthog: PostHog; survey:
>
)
}
-
-const questionTypeMap = (
- question: SurveyQuestion,
- questionIndex: number,
- appearance: SurveyAppearance,
- onSubmit: (res: string | string[] | number | null) => void,
- closeSurveyPopup: () => void
-): JSX.Element => {
- const mapping = {
- [SurveyQuestionType.Open]: (
-
- ),
- [SurveyQuestionType.Link]: (
-
- ),
- [SurveyQuestionType.Rating]: (
-
- ),
- [SurveyQuestionType.SingleChoice]: (
-
- ),
- [SurveyQuestionType.MultipleChoice]: (
-
- ),
- }
- return mapping[question.type]
-}
-
-const threeScaleEmojis = [dissatisfiedEmoji, neutralEmoji, dissatisfiedEmoji]
-const fiveScaleEmojis = [veryDissatisfiedEmoji, dissatisfiedEmoji, neutralEmoji, satisfiedEmoji, verySatisfiedEmoji]
-const fiveScaleNumbers = [1, 2, 3, 4, 5]
-const tenScaleNumbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
diff --git a/src/extensions/surveys/components/BottomSection.tsx b/src/extensions/surveys/components/BottomSection.tsx
index 82eb73852..c701687fb 100644
--- a/src/extensions/surveys/components/BottomSection.tsx
+++ b/src/extensions/surveys/components/BottomSection.tsx
@@ -1,4 +1,4 @@
-import * as Preact from 'preact'
+import { RefObject } from 'preact'
import { window } from '../../../utils/globals'
import { SurveyAppearance } from '../../../posthog-surveys-types'
@@ -26,7 +26,7 @@ export function BottomSection({