Skip to content

Commit

Permalink
feat(surveys): Add regex matching option (PostHog#17738)
Browse files Browse the repository at this point in the history
  • Loading branch information
neilkakkar authored Oct 4, 2023
1 parent 1db70fb commit cd60473
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 12 deletions.
45 changes: 36 additions & 9 deletions frontend/src/scenes/surveys/Survey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
SurveyType,
LinkSurveyQuestion,
RatingSurveyQuestion,
SurveyUrlMatchType,
} from '~/types'
import { FlagSelector } from 'scenes/early-access-features/EarlyAccessFeature'
import { IconCancel, IconDelete, IconPlus, IconPlusMini } from 'lib/lemon-ui/icons'
Expand All @@ -32,7 +33,7 @@ import { SurveyAppearance } from './SurveyAppearance'
import { SurveyAPIEditor } from './SurveyAPIEditor'
import { featureFlagLogic as enabledFeaturesLogic } from 'lib/logic/featureFlagLogic'
import { featureFlagLogic } from 'scenes/feature-flags/featureFlagLogic'
import { defaultSurveyFieldValues, defaultSurveyAppearance, NewSurvey } from './constants'
import { defaultSurveyFieldValues, defaultSurveyAppearance, NewSurvey, SurveyUrlMatchTypeLabels } from './constants'
import { FEATURE_FLAGS } from 'lib/constants'
import { FeatureFlagReleaseConditions } from 'scenes/feature-flags/FeatureFlagReleaseConditions'

Expand Down Expand Up @@ -61,7 +62,8 @@ export function SurveyComponent({ id }: { id?: string } = {}): JSX.Element {
}

export function SurveyForm({ id }: { id: string }): JSX.Element {
const { survey, surveyLoading, isEditingSurvey, hasTargetingFlag } = useValues(surveyLogic)
const { survey, surveyLoading, isEditingSurvey, hasTargetingFlag, urlMatchTypeValidationError } =
useValues(surveyLogic)
const { loadSurvey, editingSurvey, setSurveyValue, setDefaultForQuestionType } = useActions(surveyLogic)
const { featureFlags } = useValues(enabledFeaturesLogic)

Expand Down Expand Up @@ -405,12 +407,31 @@ export function SurveyForm({ id }: { id: string }): JSX.Element {
<Field name="conditions">
{({ value, onChange }) => (
<>
<PureField label="URL contains:">
<LemonInput
value={value?.url}
onChange={(urlVal) => onChange({ ...value, url: urlVal })}
placeholder="ex: https://app.posthog.com"
/>
<PureField
label="URL targeting"
error={urlMatchTypeValidationError}
info="Targeting by regex or exact match requires atleast version 1.82 of posthog-js"
>
<div className="flex flex-row gap-2 items-center">
URL
<LemonSelect
value={value?.urlMatchType || SurveyUrlMatchType.Contains}
onChange={(matchTypeVal) => {
onChange({ ...value, urlMatchType: matchTypeVal })
}}
data-attr="survey-url-matching-type"
options={Object.keys(SurveyUrlMatchTypeLabels).map((key) => ({
label: SurveyUrlMatchTypeLabels[key],
value: key,
}))}
/>
<LemonInput
value={value?.url}
onChange={(urlVal) => onChange({ ...value, url: urlVal })}
placeholder="ex: https://app.posthog.com"
fullWidth
/>
</div>
</PureField>
<PureField label="Selector matches:">
<LemonInput
Expand Down Expand Up @@ -565,7 +586,13 @@ export function SurveyReleaseSummary({
{survey.conditions?.url && (
<div className="flex flex-col font-medium gap-1">
<div className="flex-row">
<span>URL contains:</span>{' '}
<span>
URL{' '}
{SurveyUrlMatchTypeLabels[
survey.conditions?.urlMatchType || SurveyUrlMatchType.Contains
].slice(2)}
:
</span>{' '}
<span className="simple-tag tag-light-blue text-primary-alt">{survey.conditions.url}</span>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/surveys/Surveys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ export function Surveys(): JSX.Element {
{
title: 'Question type',
render: function RenderResponses(_, survey) {
return survey.questions.length === 1
return survey.questions?.length === 1
? SurveyQuestionLabel[survey.questions[0].type]
: 'Multiple'
},
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/scenes/surveys/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FeatureFlagFilters, Survey, SurveyQuestionType, SurveyType } from '~/types'
import { FeatureFlagFilters, Survey, SurveyQuestionType, SurveyType, SurveyUrlMatchType } from '~/types'

export const SURVEY_EVENT_NAME = 'survey sent'
export const SURVEY_RESPONSE_PROPERTY = '$survey_response'
Expand All @@ -11,6 +11,12 @@ export const SurveyQuestionLabel = {
[SurveyQuestionType.MultipleChoice]: 'Multiple choice select',
}

export const SurveyUrlMatchTypeLabels = {
[SurveyUrlMatchType.Contains]: '∋ contains',
[SurveyUrlMatchType.Regex]: '∼ matches regex',
[SurveyUrlMatchType.Exact]: '= equals',
}

export const defaultSurveyAppearance = {
backgroundColor: '#eeeded',
submitButtonText: 'Submit',
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/scenes/surveys/surveyLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
SurveyQuestionBase,
SurveyQuestionType,
SurveyType,
SurveyUrlMatchType,
} from '~/types'
import type { surveyLogicType } from './surveyLogicType'
import { DataTableNode, InsightVizNode, NodeKind } from '~/queries/schema'
Expand Down Expand Up @@ -379,6 +380,19 @@ export const surveyLogic = kea<surveyLogicType>([
return !!survey.targeting_flag || !!survey.targeting_flag_filters
},
],
urlMatchTypeValidationError: [
(s) => [s.survey],
(survey): string | null => {
if (survey.conditions?.urlMatchType === SurveyUrlMatchType.Regex && survey.conditions.url) {
try {
new RegExp(survey.conditions.url)
} catch (e: any) {
return e.message
}
}
return null
},
],
}),
forms(({ actions, props, values }) => ({
survey: {
Expand All @@ -397,6 +411,8 @@ export const surveyLogic = kea<surveyLogicType>([
}
: {}),
})),
// controlled using a PureField in the form
urlMatchType: values.urlMatchTypeValidationError,
}),
submit: async (surveyPayload) => {
let surveyPayloadWithTargetingFlagFilters = surveyPayload
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2090,7 +2090,13 @@ export interface Survey {
linked_flag: FeatureFlagBasicType | null
targeting_flag: FeatureFlagBasicType | null
targeting_flag_filters: Pick<FeatureFlagFilters, 'groups'> | undefined
conditions: { url: string; selector: string; is_headless?: boolean; seenSurveyWaitPeriodInDays?: number } | null
conditions: {
url: string
selector: string
is_headless?: boolean
seenSurveyWaitPeriodInDays?: number
urlMatchType?: SurveyUrlMatchType
} | null
appearance: SurveyAppearance
questions: (BasicSurveyQuestion | LinkSurveyQuestion | RatingSurveyQuestion | MultipleSurveyQuestion)[]
created_at: string
Expand All @@ -2101,6 +2107,12 @@ export interface Survey {
remove_targeting_flag?: boolean
}

export enum SurveyUrlMatchType {
Exact = 'exact',
Contains = 'icontains',
Regex = 'regex',
}

export enum SurveyType {
Popover = 'popover',
Button = 'button',
Expand Down

0 comments on commit cd60473

Please sign in to comment.