Skip to content

Commit

Permalink
feat(surveys): Link/interview type (#16333)
Browse files Browse the repository at this point in the history
* add link type to surveys

* update link survey type to appearances

* add open link to preview

* Update UI snapshots for `chromium` (1)

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
liyiy and github-actions[bot] authored Jul 3, 2023
1 parent 571ce35 commit ae50265
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 31 deletions.
27 changes: 20 additions & 7 deletions frontend/src/scenes/surveys/Survey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { router } from 'kea-router'
import { urls } from 'scenes/urls'
import { Field, PureField } from 'lib/forms/Field'
import { FilterLogicalOperator, SurveyQuestion, SurveyType, Survey, FeatureFlagFilters } from '~/types'
import { FilterLogicalOperator, SurveyQuestion, Survey, FeatureFlagFilters, SurveyQuestionType } from '~/types'
import { FlagSelector } from 'scenes/early-access-features/EarlyAccessFeature'
import { PropertyFilters } from 'lib/components/PropertyFilters/PropertyFilters'
import { IconCancel, IconDelete, IconErrorOutline, IconPlus, IconPlusMini, IconSubArrowRight } from 'lib/lemon-ui/icons'
Expand Down Expand Up @@ -100,12 +100,6 @@ export function SurveyForm({ id }: { id: string }): JSX.Element {
<Field name="description" label="Description (optional)">
<LemonTextArea data-attr="survey-description" />
</Field>
<Field name="type" label="Type" className="w-max">
<LemonSelect
data-attr="survey-type"
options={[{ label: 'Popover', value: SurveyType.Popover }]}
/>
</Field>
<Field
name="linked_flag_id"
label="Link feature flag (optional)"
Expand Down Expand Up @@ -134,9 +128,25 @@ export function SurveyForm({ id }: { id: string }): JSX.Element {
</Field>
{survey.questions.map((question: SurveyQuestion, index: number) => (
<Group name={`questions.${index}`} key={index}>
<Field name="type" label="Type" className="w-max">
<LemonSelect
options={[
{ label: 'Open text', value: SurveyQuestionType.Open },
{ label: 'Link', value: SurveyQuestionType.Link },
]}
/>
</Field>
<Field name="question" label="Question">
<LemonInput value={question.question} />
</Field>
<Field name="description" label="Question description (optional)">
<LemonTextArea value={question.description || ''} />
</Field>
{question.type === SurveyQuestionType.Link && (
<Field name="link" label="Link" info="Make sure to include https:// in the url.">
<LemonInput value={question.link || ''} placeholder="https://posthog.com" />
</Field>
)}
</Group>
))}
<PureField label="Targeting (optional)" className="mt-4">
Expand Down Expand Up @@ -250,10 +260,13 @@ export function SurveyForm({ id }: { id: string }): JSX.Element {
<Field name="appearance" label="">
{({ value, onChange }) => (
<SurveyAppearance
type={survey.questions[0].type}
question={survey.questions[0].question}
description={survey.questions[0].description}
onAppearanceChange={(appearance) => {
onChange(appearance)
}}
link={survey.questions[0].link}
appearance={value || defaultSurveyAppearance}
/>
)}
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/scenes/surveys/SurveyAppearance.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
padding-top: 4px;
padding-bottom: 4px;
text-align: center;
font-size: 16px;
color: 'black'; //changeable: textColor
}

Expand Down Expand Up @@ -122,4 +123,11 @@
.bottom-section {
padding-bottom: 0.5rem;
}

.description {
font-size: 14px;
margin-top: 0.75rem;
margin-bottom: 0.75rem;
text-align: center;
}
}
68 changes: 51 additions & 17 deletions frontend/src/scenes/surveys/SurveyAppearance.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
import './SurveyAppearance.scss'
import { LemonInput } from '@posthog/lemon-ui'
import { useState } from 'react'
import { SurveyAppearance as SurveyAppearanceType } from '~/types'
import { SurveyAppearance as SurveyAppearanceType, SurveyQuestionType } from '~/types'
import { defaultSurveyAppearance } from './surveyLogic'

interface SurveyAppearanceProps {
// type: string
type: SurveyQuestionType
question: string
appearance: SurveyAppearanceType
description?: string | null
link?: string | null
readOnly?: boolean
onAppearanceChange: (appearance: SurveyAppearanceType) => void
}
export function SurveyAppearance({
type,
question,
appearance,
description,
link,
readOnly,
onAppearanceChange,
}: SurveyAppearanceProps): JSX.Element {
return (
<>
<h3 className="mb-4 text-center">Preview</h3>
<BaseAppearance question={question} appearance={appearance} />
<BaseAppearance
type={type}
question={question}
description={description}
appearance={appearance}
link={link}
/>
{!readOnly && (
<div className="flex flex-col">
<div className="mt-2">Background color</div>
<LemonInput
value={appearance?.backgroundColor}
onChange={(backgroundColor) => onAppearanceChange({ ...appearance, backgroundColor })}
/>
<div className="mt-2">Text color</div>
<div className="mt-2">Question text color</div>
<LemonInput
value={appearance?.textColor}
onChange={(textColor) => onAppearanceChange({ ...appearance, textColor })}
Expand All @@ -37,6 +48,16 @@ export function SurveyAppearance({
value={appearance?.submitButtonColor}
onChange={(submitButtonColor) => onAppearanceChange({ ...appearance, submitButtonColor })}
/>
<div className="mt-2">Description text color</div>
<LemonInput
value={appearance?.descriptionTextColor || defaultSurveyAppearance.descriptionTextColor}
onChange={(descriptionTextColor) => onAppearanceChange({ ...appearance, descriptionTextColor })}
/>
<div className="mt-2">Submit button text</div>
<LemonInput
value={appearance?.submitButtonText || defaultSurveyAppearance.submitButtonText}
onChange={(submitButtonText) => onAppearanceChange({ ...appearance, submitButtonText })}
/>
</div>
)}
</>
Expand Down Expand Up @@ -67,9 +88,19 @@ const posthogLogoSVG = (
</svg>
)
// This should be synced to the UI of the surveys app plugin
function BaseAppearance({ question, appearance }: { question: string; appearance: SurveyAppearanceType }): JSX.Element {
const [hasText, setHasText] = useState(false)

function BaseAppearance({
type,
question,
appearance,
description,
link,
}: {
type: SurveyQuestionType
question: string
appearance: SurveyAppearanceType
description?: string | null
link?: string | null
}): JSX.Element {
return (
<form className="survey-form" style={{ backgroundColor: appearance.backgroundColor }}>
<div className="survey-box">
Expand All @@ -86,23 +117,26 @@ function BaseAppearance({ question, appearance }: { question: string; appearance
<div className="survey-question" style={{ color: appearance.textColor }}>
{question}
</div>
<textarea
className="survey-textarea"
name="survey"
rows={4}
onChange={(event) => setHasText(!!event?.target.value)}
/>
{description && (
<div className="description" style={{ color: appearance.descriptionTextColor }}>
{description}
</div>
)}
{type === SurveyQuestionType.Open && (
<textarea className="survey-textarea" name="survey" rows={4} />
)}
</div>
<div className="bottom-section">
<div className="buttons">
<button
className="form-submit"
type="button"
disabled={!hasText}
onClick={() => {}}
onClick={() => {
link && type === SurveyQuestionType.Link ? window.open(link) : null
}}
style={{ backgroundColor: appearance.submitButtonColor }}
>
Submit
{appearance.submitButtonText || 'Submit'}
</button>
</div>
<div className="footer-branding">powered by {posthogLogoSVG} PostHog</div>
Expand Down
16 changes: 13 additions & 3 deletions frontend/src/scenes/surveys/SurveyView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { More } from 'lib/lemon-ui/LemonButton/More'
import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton'
import { LemonTabs } from 'lib/lemon-ui/LemonTabs'
import { capitalizeFirstLetter } from 'lib/utils'
import { SurveyType } from 'posthog-js'
import { useState, useEffect } from 'react'
import { pluginsLogic } from 'scenes/plugins/pluginsLogic'
import { urls } from 'scenes/urls'
Expand All @@ -17,6 +16,7 @@ import { surveysLogic } from './surveysLogic'
import { PageHeader } from 'lib/components/PageHeader'
import { SurveyReleaseSummary } from './Survey'
import { SurveyAppearance } from './SurveyAppearance'
import { SurveyQuestionType } from 'posthog-js'

export function SurveyView({ id }: { id: string }): JSX.Element {
const { survey, dataTableQuery, surveyLoading, surveyPlugin, surveyMetricsQueries } = useValues(surveyLogic)
Expand Down Expand Up @@ -112,11 +112,18 @@ export function SurveyView({ id }: { id: string }): JSX.Element {
<div className="flex flex-row">
<div className="flex flex-col w-full">
<span className="card-secondary mt-4">Type</span>
<span>{capitalizeFirstLetter(SurveyType.Popover)}</span>
<span className="card-secondary mt-4">Questions</span>
<span>{capitalizeFirstLetter(survey.questions[0].type)}</span>
<span className="card-secondary mt-4">Question</span>
{survey.questions.map((q, idx) => (
<span key={idx}>{q.question}</span>
))}
{survey.questions[0].type === SurveyQuestionType.Link && (
<>
<span className="card-secondary mt-4">Link url</span>
<span>{survey.questions[0].link}</span>
</>
)}

<span className="card-secondary mt-4">Linked feature flag</span>
{survey.linked_flag ? (
<Link to={urls.featureFlag(survey.linked_flag.id)}>
Expand Down Expand Up @@ -198,8 +205,11 @@ export function SurveyView({ id }: { id: string }): JSX.Element {
/>
<div className="mt-6">
<SurveyAppearance
type={survey.questions[0].type}
appearance={survey.appearance || defaultSurveyAppearance}
question={survey.questions[0].question}
description={survey.questions[0].description}
link={survey.questions[0].link}
readOnly={true}
onAppearanceChange={() => {}}
/>
Expand Down
17 changes: 14 additions & 3 deletions frontend/src/scenes/surveys/surveyLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,19 @@ export interface NewSurvey
targeting_flag_filters: Pick<FeatureFlagFilters, 'groups'> | undefined
}

export const defaultSurveyAppearance = { backgroundColor: 'white', submitButtonColor: '#2C2C2C', textColor: 'black' }
export const defaultSurveyAppearance = {
backgroundColor: 'white',
submitButtonColor: '#2C2C2C',
textColor: 'black',
submitButtonText: 'Submit',
descriptionTextColor: 'black',
}

const NEW_SURVEY: NewSurvey = {
id: 'new',
name: '',
description: '',
questions: [{ type: SurveyQuestionType.Open, question: '' }],
questions: [{ type: SurveyQuestionType.Open, question: '', link: null }],
type: SurveyType.Popover,
linked_flag_id: undefined,
targeting_flag_filters: undefined,
Expand Down Expand Up @@ -311,7 +317,12 @@ export const surveyLogic = kea<surveyLogicType>([
defaults: { ...NEW_SURVEY } as NewSurvey | Survey,
errors: ({ name, questions }) => ({
name: !name && 'Please enter a name.',
questions: questions.map(({ question }) => ({ question: !question && 'Please enter a question.' })),
questions: questions.map((question) => ({
question: !question.question && 'Please enter a question.',
...(question.type === SurveyQuestionType.Link
? { link: !question.link && 'Please enter a url for the link.' }
: {}),
})),
}),
submit: async (surveyPayload) => {
const surveyPayloadWithTargetingFlagFilters = {
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2060,13 +2060,16 @@ export interface SurveyAppearance {
backgroundColor?: string
submitButtonColor?: string
textColor?: string
submitButtonText?: string
descriptionTextColor?: string
}

export interface SurveyQuestion {
type: SurveyQuestionType
question: string
description?: string | null
required?: boolean
link?: string | null
link: string | null
choices?: string[] | null
}

Expand Down

0 comments on commit ae50265

Please sign in to comment.