Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(surveys): enable button text per question instead #18623

Merged
merged 10 commits into from
Nov 15, 2023
Binary file modified frontend/__snapshots__/scenes-app-insights--stickiness--webkit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-surveys--new-survey.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-surveys--survey-templates.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 1 addition & 8 deletions frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createPostHogWidgetNode } from 'scenes/notebooks/Nodes/NodeWrapper'
import { FeatureFlagBasicType, NotebookNodeType, Survey, SurveyQuestionType } from '~/types'
import { FeatureFlagBasicType, NotebookNodeType, Survey } from '~/types'
import { BindLogic, useActions, useValues } from 'kea'
import { IconSurveys } from 'lib/lemon-ui/icons'
import { LemonDivider } from '@posthog/lemon-ui'
Expand Down Expand Up @@ -81,13 +81,6 @@ const Component = ({ attributes }: NotebookNodeProps<NotebookNodeSurveyAttribute
type={survey.questions[0].type}
surveyQuestionItem={survey.questions[0]}
appearance={survey.appearance || defaultSurveyAppearance}
question={survey.questions[0].question}
description={survey.questions[0].description}
link={
survey.questions[0].type === SurveyQuestionType.Link
? survey.questions[0].link
: undefined
}
/>
</div>
</div>
Expand Down
86 changes: 37 additions & 49 deletions frontend/src/scenes/surveys/SurveyAppearance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
SurveyQuestionType,
MultipleSurveyQuestion,
AvailableFeature,
BasicSurveyQuestion,
LinkSurveyQuestion,
} from '~/types'
import { defaultSurveyAppearance } from './constants'
import {
Expand All @@ -28,11 +30,8 @@ import { sanitizeHTML } from './utils'

interface SurveyAppearanceProps {
type: SurveyQuestionType
question: string
appearance: SurveyAppearanceType
surveyQuestionItem: SurveyQuestion
description?: string | null
link?: string | null
preview?: boolean
}

Expand Down Expand Up @@ -87,11 +86,8 @@ const Button = ({

export function SurveyAppearance({
type,
question,
appearance,
surveyQuestionItem,
description,
link,
preview,
}: SurveyAppearanceProps): JSX.Element {
return (
Expand All @@ -101,8 +97,6 @@ export function SurveyAppearance({
preview={preview}
ratingSurveyQuestion={surveyQuestionItem as RatingSurveyQuestion}
appearance={appearance}
question={question}
description={description}
onSubmit={() => undefined}
/>
)}
Expand All @@ -112,20 +106,15 @@ export function SurveyAppearance({
preview={preview}
multipleChoiceQuestion={surveyQuestionItem as MultipleSurveyQuestion}
appearance={appearance}
question={question}
description={description}
onSubmit={() => undefined}
/>
)}
{(surveyQuestionItem.type === SurveyQuestionType.Open ||
surveyQuestionItem.type === SurveyQuestionType.Link) && (
<BaseAppearance
preview={preview}
type={type}
question={question}
description={description}
question={surveyQuestionItem}
appearance={appearance}
link={link}
onSubmit={() => undefined}
/>
)}
Expand All @@ -143,11 +132,6 @@ export function Customization({ appearance, surveyQuestionItem, onAppearanceChan
<></>
</PayGateMini>
)}
<div className="mt-2">Button text</div>
<LemonInput
value={appearance?.submitButtonText || defaultSurveyAppearance.submitButtonText}
onChange={(submitButtonText) => onAppearanceChange({ ...appearance, submitButtonText })}
/>
<div className="mt-2">Background color</div>
<LemonInput
value={appearance?.backgroundColor}
Expand Down Expand Up @@ -234,20 +218,14 @@ export function Customization({ appearance, surveyQuestionItem, onAppearanceChan

// This should be synced to the UI of the surveys app plugin
export function BaseAppearance({
type,
question,
appearance,
onSubmit,
description,
link,
preview,
}: {
type: SurveyQuestionType
question: string
question: BasicSurveyQuestion | LinkSurveyQuestion
appearance: SurveyAppearanceType
onSubmit: () => void
description?: string | null
link?: string | null
preview?: boolean
}): JSX.Element {
const [textColor, setTextColor] = useState('black')
Expand Down Expand Up @@ -284,14 +262,20 @@ export function BaseAppearance({
</div>
)}
<div className="question-textarea-wrapper">
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitizeHTML(question) }} />
<div
className="survey-question"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(question.question) }}
/>
{/* Using dangerouslySetInnerHTML is safe here, because it's taking the user's input and showing it to the same user.
They can try passing in arbitrary scripts, but it would show up only for them, so it's like trying to XSS yourself, where
you already have all the data. Furthermore, sanitization should catch all obvious attempts */}
{description && (
<div className="description" dangerouslySetInnerHTML={{ __html: sanitizeHTML(description) }} />
{question.description && (
<div
className="description"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(question.description) }}
/>
)}
{type === SurveyQuestionType.Open && (
{question.type === SurveyQuestionType.Open && (
<textarea
{...(preview ? { tabIndex: -1 } : null)}
style={{
Expand All @@ -310,11 +294,11 @@ export function BaseAppearance({
<Button
{...(preview ? { tabIndex: -1 } : null)}
appearance={appearance}
link={link}
link={question.type === SurveyQuestionType.Link ? question.link : null}
onSubmit={onSubmit}
type={type}
type={question.type}
>
{appearance.submitButtonText}
{question.buttonText || appearance.submitButtonText}
</Button>
</div>

Expand Down Expand Up @@ -446,16 +430,12 @@ const EmojiRating = ({
export function SurveyRatingAppearance({
ratingSurveyQuestion,
appearance,
question,
onSubmit,
description,
preview,
}: {
ratingSurveyQuestion: RatingSurveyQuestion
appearance: SurveyAppearanceType
question: string
onSubmit: () => void
description?: string | null
preview?: boolean
}): JSX.Element {
const [textColor, setTextColor] = useState('black')
Expand Down Expand Up @@ -491,9 +471,15 @@ export function SurveyRatingAppearance({
</button>
</div>
)}
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitizeHTML(question) }} />
{description && (
<div className="description" dangerouslySetInnerHTML={{ __html: sanitizeHTML(description) }} />
<div
className="survey-question"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(ratingSurveyQuestion.question) }}
/>
{ratingSurveyQuestion.description && (
<div
className="description"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(ratingSurveyQuestion.description) }}
/>
)}
<div className="rating-section">
<div className="rating-options">
Expand Down Expand Up @@ -524,7 +510,7 @@ export function SurveyRatingAppearance({
appearance={appearance}
onSubmit={onSubmit}
>
{appearance.submitButtonText}
{ratingSurveyQuestion.buttonText || appearance.submitButtonText}
</Button>
</div>

Expand All @@ -543,17 +529,13 @@ export function SurveyRatingAppearance({
export function SurveyMultipleChoiceAppearance({
multipleChoiceQuestion,
appearance,
question,
onSubmit,
description,
preview,
initialChecked,
}: {
multipleChoiceQuestion: MultipleSurveyQuestion
appearance: SurveyAppearanceType
question: string
onSubmit: () => void
description?: string | null
preview?: boolean
initialChecked?: number[]
}): JSX.Element {
Expand Down Expand Up @@ -591,9 +573,15 @@ export function SurveyMultipleChoiceAppearance({
</button>
</div>
)}
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitizeHTML(question) }} />
{description && (
<div className="description" dangerouslySetInnerHTML={{ __html: sanitizeHTML(description) }} />
<div
className="survey-question"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(multipleChoiceQuestion.question) }}
/>
{multipleChoiceQuestion.description && (
<div
className="description"
dangerouslySetInnerHTML={{ __html: sanitizeHTML(multipleChoiceQuestion.description) }}
/>
)}
<div className="multiple-choice-options">
{(multipleChoiceQuestion.choices || []).map((choice, idx) => (
Expand All @@ -612,7 +600,7 @@ export function SurveyMultipleChoiceAppearance({
<div className="bottom-section">
<div className="buttons">
<Button {...(preview ? { tabIndex: -1 } : null)} appearance={appearance} onSubmit={onSubmit}>
{appearance.submitButtonText}
{multipleChoiceQuestion.buttonText || appearance.submitButtonText}
liyiy marked this conversation as resolved.
Show resolved Hide resolved
</Button>
</div>

Expand Down
Loading
Loading