Skip to content

Commit

Permalink
cleaned code for queries
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasheriques committed Feb 12, 2025
1 parent 29efd3e commit 00c5983
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 61 deletions.
60 changes: 33 additions & 27 deletions frontend/src/scenes/surveys/SurveyAnswerFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useActions, useValues } from 'kea'
import { PropertyValue } from 'lib/components/PropertyFilters/components/PropertyValue'
import { allOperatorsMapping } from 'lib/utils'

import { AnyPropertyFilter, PropertyFilterType, PropertyOperator, Survey, SurveyQuestionType } from '~/types'
import { EventPropertyFilter, PropertyFilterType, PropertyOperator, Survey, SurveyQuestionType } from '~/types'

import { surveyLogic } from './surveyLogic'

Expand All @@ -20,8 +20,8 @@ const OPERATOR_OPTIONS: Record<SurveyQuestionType, OperatorOption[]> = {
[SurveyQuestionType.Rating]: [
{ label: allOperatorsMapping[PropertyOperator.Exact], value: PropertyOperator.Exact },
{ label: allOperatorsMapping[PropertyOperator.IsNot], value: PropertyOperator.IsNot },
{ label: allOperatorsMapping[PropertyOperator.GreaterThan], value: PropertyOperator.GreaterThan },
{ label: allOperatorsMapping[PropertyOperator.LessThan], value: PropertyOperator.LessThan },
{ label: allOperatorsMapping[PropertyOperator.Regex], value: PropertyOperator.Regex },
{ label: allOperatorsMapping[PropertyOperator.NotRegex], value: PropertyOperator.NotRegex },
],
[SurveyQuestionType.SingleChoice]: [
{ label: allOperatorsMapping[PropertyOperator.IContains], value: PropertyOperator.IContains },
Expand Down Expand Up @@ -59,19 +59,22 @@ export function SurveyAnswerFilters(): JSX.Element {
)

if (filterIndex >= 0) {
// Ensure we're working with an EventPropertyFilter
const existingFilter = newFilters[filterIndex]
newFilters[filterIndex] = {
...newFilters[filterIndex],
...existingFilter,
[field]: value,
type: PropertyFilterType.Event, // Ensure type is always set
}
setAnswerFilters(newFilters)
}
}

const getFilterForQuestion = (questionIndex: number): AnyPropertyFilter | undefined => {
if (questionIndex === 0) {
return answerFilters.find((f) => f.key === '$survey_response')
}
return answerFilters.find((f) => f.key === `$survey_response_${questionIndex}`)
const getFilterForQuestion = (questionIndex: number): EventPropertyFilter | undefined => {
const filter = answerFilters.find(
(f) => f.key === (questionIndex === 0 ? '$survey_response' : `$survey_response_${questionIndex}`)
)
return filter
}

return (
Expand Down Expand Up @@ -111,24 +114,27 @@ export function SurveyAnswerFilters(): JSX.Element {
/>
</div>
<div className="col-span-2">
{![PropertyOperator.IsSet, PropertyOperator.IsNotSet].includes(
currentFilter?.operator as PropertyOperator
) && (
<PropertyValue
propertyKey={index === 0 ? '$survey_response' : `$survey_response_${index}`}
type={PropertyFilterType.Event}
operator={currentFilter?.operator as PropertyOperator}
value={currentFilter?.value || []}
onSet={(value: string[]) => handleUpdateFilter(index, 'value', value)}
placeholder={
question.type === SurveyQuestionType.Rating
? 'Enter a number'
: question.type === SurveyQuestionType.Open
? 'Enter text to match'
: 'Select values'
}
/>
)}
{currentFilter?.operator &&
![PropertyOperator.IsSet, PropertyOperator.IsNotSet].includes(
currentFilter.operator
) && (
<PropertyValue
propertyKey={
index === 0 ? '$survey_response' : `$survey_response_${index}`
}
type={PropertyFilterType.Event}
operator={currentFilter.operator}
value={currentFilter.value || []}
onSet={(value: any) => handleUpdateFilter(index, 'value', value)}
placeholder={
question.type === SurveyQuestionType.Rating
? 'Enter a number'
: question.type === SurveyQuestionType.Open
? 'Enter text to match'
: 'Select values'
}
/>
)}
</div>
</div>
)
Expand Down
153 changes: 153 additions & 0 deletions frontend/src/scenes/surveys/surveyLogic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useMocks } from '~/mocks/jest'
import { initKeaTests } from '~/test/init'
import {
AnyPropertyFilter,
EventPropertyFilter,
PropertyFilterType,
PropertyOperator,
Survey,
Expand Down Expand Up @@ -1555,3 +1556,155 @@ describe('survey filters', () => {
})
})
})

describe('answer filters', () => {
let logic: ReturnType<typeof surveyLogic.build>

beforeEach(() => {
initKeaTests()
logic = surveyLogic({ id: 'new' })
logic.mount()
})

it('applies answer filters to queries', async () => {
const answerFilter: EventPropertyFilter = {
key: '$survey_response',
value: 'test response',
operator: PropertyOperator.IContains,
type: PropertyFilterType.Event,
}

await expectLogic(logic, () => {
logic.actions.loadSurveySuccess(MULTIPLE_CHOICE_SURVEY)
logic.actions.setAnswerFilters([answerFilter])
})
.toDispatchActions(['loadSurveySuccess', 'setAnswerFilters'])
.toMatchValues({
answerFilters: [answerFilter],
dataTableQuery: partial({
source: partial({
properties: expect.arrayContaining([answerFilter]),
}),
}),
})
})

it('only applies relevant answer filter to question-specific queries', async () => {
const answerFilters: EventPropertyFilter[] = [
{
key: '$survey_response',
value: 'first question',
operator: PropertyOperator.IContains,
type: PropertyFilterType.Event,
},
{
key: '$survey_response_1',
value: 'second question',
operator: PropertyOperator.IContains,
type: PropertyFilterType.Event,
},
]

await expectLogic(logic, () => {
logic.actions.loadSurveySuccess({
...MULTIPLE_CHOICE_SURVEY,
questions: [
MULTIPLE_CHOICE_SURVEY.questions[0],
{ ...MULTIPLE_CHOICE_SURVEY.questions[0], question: 'Second question' },
],
})
logic.actions.setAnswerFilters(answerFilters)
})
.toDispatchActions(['loadSurveySuccess', 'setAnswerFilters'])
.toMatchValues({
answerFilters: answerFilters,
})

// Mock the query response
useMocks({
post: {
'/api/environments/:team_id/query/': () => [
200,
{
results: [
[336, '"Tutorials"'],
[312, '"Customer case studies"'],
],
},
],
},
})

// Load results for first question
await expectLogic(logic, () => {
logic.actions.loadSurveyMultipleChoiceResults({ questionIndex: 0 })
}).toMatchValues({
dataTableQuery: partial({
source: partial({
properties: expect.arrayContaining([answerFilters[0]]),
}),
}),
})

// Load results for second question
await expectLogic(logic, () => {
logic.actions.loadSurveyMultipleChoiceResults({ questionIndex: 1 })
}).toMatchValues({
dataTableQuery: partial({
source: partial({
properties: expect.arrayContaining([answerFilters[1]]),
}),
}),
})
})

it('can add and remove answer filters', async () => {
const firstFilter: EventPropertyFilter = {
key: '$survey_response',
value: 'first response',
operator: PropertyOperator.IContains,
type: PropertyFilterType.Event,
}
const secondFilter: EventPropertyFilter = {
key: '$survey_response_1',
value: 'second response',
operator: PropertyOperator.IContains,
type: PropertyFilterType.Event,
}

await expectLogic(logic, () => {
logic.actions.loadSurveySuccess(MULTIPLE_CHOICE_SURVEY)
logic.actions.addAnswerFilter(firstFilter)
logic.actions.addAnswerFilter(secondFilter)
})
.toDispatchActions(['loadSurveySuccess', 'addAnswerFilter', 'addAnswerFilter'])
.toMatchValues({
answerFilters: expect.arrayContaining([firstFilter, secondFilter]),
})

await expectLogic(logic, () => {
logic.actions.removeAnswerFilter(0)
})
.toDispatchActions(['removeAnswerFilter'])
.toMatchValues({
answerFilters: [secondFilter],
})
})

it('reloads survey results when answer filters change', async () => {
await expectLogic(logic, () => {
logic.actions.loadSurveySuccess(MULTIPLE_CHOICE_SURVEY)
}).toDispatchActions(['loadSurveySuccess'])

const answerFilter: EventPropertyFilter = {
key: '$survey_response',
value: 'test response',
operator: PropertyOperator.IContains,
type: PropertyFilterType.Event,
}

await expectLogic(logic, () => {
logic.actions.setAnswerFilters([answerFilter])
}).toDispatchActions(['setAnswerFilters', 'loadSurveyUserStats', 'loadSurveyMultipleChoiceResults'])
})
})
Loading

0 comments on commit 00c5983

Please sign in to comment.