diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey.png b/frontend/__snapshots__/scenes-app-surveys--new-survey.png
index 42ecadfbd13a9..7919d71d4d68e 100644
Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey.png differ
diff --git a/frontend/__snapshots__/scenes-app-surveys--surveys-list.png b/frontend/__snapshots__/scenes-app-surveys--surveys-list.png
index c376b70a4e31f..8f5f6642dbecc 100644
Binary files a/frontend/__snapshots__/scenes-app-surveys--surveys-list.png and b/frontend/__snapshots__/scenes-app-surveys--surveys-list.png differ
diff --git a/frontend/src/scenes/feature-flags/featureFlagLogic.ts b/frontend/src/scenes/feature-flags/featureFlagLogic.ts
index aeb4b9471f764..5f33ae64bd556 100644
--- a/frontend/src/scenes/feature-flags/featureFlagLogic.ts
+++ b/frontend/src/scenes/feature-flags/featureFlagLogic.ts
@@ -42,7 +42,7 @@ import { userLogic } from 'scenes/userLogic'
import { newDashboardLogic } from 'scenes/dashboard/newDashboardLogic'
import { dashboardsLogic } from 'scenes/dashboard/dashboards/dashboardsLogic'
import { NEW_EARLY_ACCESS_FEATURE } from 'scenes/early-access-features/earlyAccessFeatureLogic'
-import { NEW_SURVEY, NewSurvey } from 'scenes/surveys/surveyLogic'
+import { NEW_SURVEY, NewSurvey } from 'scenes/surveys/constants'
const getDefaultRollbackCondition = (): FeatureFlagRollbackConditions => ({
operator: 'gt',
diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx
index 700e1ca60a190..f58e709422962 100644
--- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx
+++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx
@@ -8,7 +8,8 @@ import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton'
import { notebookNodeLogic } from './notebookNodeLogic'
import { JSONContent, NotebookNodeViewProps } from '../Notebook/utils'
import { buildFlagContent } from './NotebookNodeFlag'
-import { defaultSurveyAppearance, surveyLogic } from 'scenes/surveys/surveyLogic'
+import { surveyLogic } from 'scenes/surveys/surveyLogic'
+import { defaultSurveyAppearance } from 'scenes/surveys/constants'
import { StatusTag } from 'scenes/surveys/Surveys'
import { SurveyResult } from 'scenes/surveys/SurveyView'
import { SurveyAppearance } from 'scenes/surveys/SurveyAppearance'
diff --git a/frontend/src/scenes/surveys/Survey.tsx b/frontend/src/scenes/surveys/Survey.tsx
index 0dd3b5a4667f7..65f9af689976d 100644
--- a/frontend/src/scenes/surveys/Survey.tsx
+++ b/frontend/src/scenes/surveys/Survey.tsx
@@ -1,5 +1,5 @@
import { SceneExport } from 'scenes/sceneTypes'
-import { NewSurvey, defaultSurveyAppearance, defaultSurveyFieldValues, surveyLogic } from './surveyLogic'
+import { surveyLogic } from './surveyLogic'
import { BindLogic, useActions, useValues } from 'kea'
import { Form, Group } from 'kea-forms'
import { PageHeader } from 'lib/components/PageHeader'
@@ -31,6 +31,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, SurveyQuestionLabel, NewSurvey } from './constants'
import { FEATURE_FLAGS } from 'lib/constants'
import { FeatureFlagReleaseConditions } from 'scenes/feature-flags/FeatureFlagReleaseConditions'
@@ -139,17 +140,26 @@ export function SurveyForm({ id }: { id: string }): JSX.Element {
)
}}
options={[
- { label: 'Open text', value: SurveyQuestionType.Open },
- { label: 'Link', value: SurveyQuestionType.Link },
- { label: 'Rating', value: SurveyQuestionType.Rating },
+ {
+ label: SurveyQuestionLabel[SurveyQuestionType.Open],
+ value: SurveyQuestionType.Open,
+ },
+ {
+ label: SurveyQuestionLabel[SurveyQuestionType.Link],
+ value: SurveyQuestionType.Link,
+ },
+ {
+ label: SurveyQuestionLabel[SurveyQuestionType.Rating],
+ value: SurveyQuestionType.Rating,
+ },
...(featureFlags[FEATURE_FLAGS.SURVEYS_MULTIPLE_CHOICE]
? [
{
- label: 'Single choice select',
+ label: SurveyQuestionLabel[SurveyQuestionType.SingleChoice],
value: SurveyQuestionType.SingleChoice,
},
{
- label: 'Multiple choice select',
+ label: SurveyQuestionLabel[SurveyQuestionType.MultipleChoice],
value: SurveyQuestionType.MultipleChoice,
},
]
diff --git a/frontend/src/scenes/surveys/SurveyAPIEditor.tsx b/frontend/src/scenes/surveys/SurveyAPIEditor.tsx
index 192d35c73b2b1..02fc80e8708ba 100644
--- a/frontend/src/scenes/surveys/SurveyAPIEditor.tsx
+++ b/frontend/src/scenes/surveys/SurveyAPIEditor.tsx
@@ -1,5 +1,5 @@
import { Survey } from '~/types'
-import { NewSurvey } from './surveyLogic'
+import { NewSurvey } from './constants'
import { CodeSnippet, Language } from 'lib/components/CodeSnippet'
export function SurveyAPIEditor({ survey }: { survey: Survey | NewSurvey }): JSX.Element {
diff --git a/frontend/src/scenes/surveys/SurveyAppearance.tsx b/frontend/src/scenes/surveys/SurveyAppearance.tsx
index 65e2b4fa9bb81..c8643df296bef 100644
--- a/frontend/src/scenes/surveys/SurveyAppearance.tsx
+++ b/frontend/src/scenes/surveys/SurveyAppearance.tsx
@@ -7,7 +7,7 @@ import {
SurveyQuestionType,
MultipleSurveyQuestion,
} from '~/types'
-import { defaultSurveyAppearance } from './surveyLogic'
+import { defaultSurveyAppearance } from './constants'
import {
cancel,
check,
diff --git a/frontend/src/scenes/surveys/SurveyView.tsx b/frontend/src/scenes/surveys/SurveyView.tsx
index 20aae5ae7af40..7f4fb0e241eab 100644
--- a/frontend/src/scenes/surveys/SurveyView.tsx
+++ b/frontend/src/scenes/surveys/SurveyView.tsx
@@ -10,7 +10,7 @@ import { capitalizeFirstLetter } from 'lib/utils'
import { useState, useEffect } from 'react'
import { pluginsLogic } from 'scenes/plugins/pluginsLogic'
import { Query } from '~/queries/Query/Query'
-import { defaultSurveyAppearance, surveyEventName, surveyLogic } from './surveyLogic'
+import { surveyLogic } from './surveyLogic'
import { surveysLogic } from './surveysLogic'
import { PageHeader } from 'lib/components/PageHeader'
import { SurveyReleaseSummary } from './Survey'
@@ -21,6 +21,7 @@ import { LemonBanner } from 'lib/lemon-ui/LemonBanner'
import { IconOpenInNew } from 'lib/lemon-ui/icons'
import { NodeKind } from '~/queries/schema'
import { dayjs } from 'lib/dayjs'
+import { defaultSurveyAppearance, SURVEY_EVENT_NAME } from './constants'
import { FEATURE_FLAGS } from 'lib/constants'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
@@ -326,7 +327,7 @@ function SurveyNPSResults({ survey }: { survey: Survey }): JSX.Element {
},
series: [
{
- event: surveyEventName,
+ event: SURVEY_EVENT_NAME,
kind: NodeKind.EventsNode,
custom_name: 'Promoters',
properties: [
@@ -339,7 +340,7 @@ function SurveyNPSResults({ survey }: { survey: Survey }): JSX.Element {
],
},
{
- event: surveyEventName,
+ event: SURVEY_EVENT_NAME,
kind: NodeKind.EventsNode,
custom_name: 'Passives',
properties: [
@@ -352,7 +353,7 @@ function SurveyNPSResults({ survey }: { survey: Survey }): JSX.Element {
],
},
{
- event: surveyEventName,
+ event: SURVEY_EVENT_NAME,
kind: NodeKind.EventsNode,
custom_name: 'Detractors',
properties: [
diff --git a/frontend/src/scenes/surveys/Surveys.tsx b/frontend/src/scenes/surveys/Surveys.tsx
index de69d4c030811..19f987bbeb5b0 100644
--- a/frontend/src/scenes/surveys/Surveys.tsx
+++ b/frontend/src/scenes/surveys/Surveys.tsx
@@ -1,4 +1,14 @@
-import { LemonButton, LemonTable, LemonDivider, Link, LemonTag, LemonTagType, Spinner } from '@posthog/lemon-ui'
+import {
+ LemonButton,
+ LemonDivider,
+ LemonInput,
+ LemonSelect,
+ LemonTable,
+ Link,
+ LemonTag,
+ LemonTagType,
+ Spinner,
+} from '@posthog/lemon-ui'
import { PageHeader } from 'lib/components/PageHeader'
import { More } from 'lib/lemon-ui/LemonButton/More'
import stringWithWBR from 'lib/utils/stringWithWBR'
@@ -14,13 +24,13 @@ import { LemonTabs } from 'lib/lemon-ui/LemonTabs'
import { useState } from 'react'
import { ProductIntroduction } from 'lib/components/ProductIntroduction/ProductIntroduction'
import { userLogic } from 'scenes/userLogic'
-import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton'
import { dayjs } from 'lib/dayjs'
import { VersionCheckerBanner } from 'lib/components/VersionChecker/VersionCheckerBanner'
import { teamLogic } from 'scenes/teamLogic'
import { LemonBanner } from 'lib/lemon-ui/LemonBanner'
import { IconSettings } from 'lib/lemon-ui/icons'
import { openSurveysSettingsDialog } from './SurveySettings'
+import { SurveyQuestionLabel } from './constants'
import { FEATURE_FLAGS } from 'lib/constants'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
@@ -30,34 +40,37 @@ export const scene: SceneExport = {
}
export enum SurveysTabs {
- All = 'all',
+ Active = 'active',
Yours = 'yours',
Archived = 'archived',
}
export function Surveys(): JSX.Element {
const {
- nonArchivedSurveys,
- archivedSurveys,
surveys,
+ searchedSurveys,
surveysLoading,
surveysResponsesCount,
surveysResponsesCountLoading,
usingSurveysSiteApp,
+ searchTerm,
+ filters,
+ uniqueCreators,
} = useValues(surveysLogic)
- const { deleteSurvey, updateSurvey } = useActions(surveysLogic)
+ const { deleteSurvey, updateSurvey, setSearchTerm, setSurveysFilters } = useActions(surveysLogic)
+
const { user } = useValues(userLogic)
const { featureFlags } = useValues(featureFlagLogic)
const { currentTeam } = useValues(teamLogic)
const surveysPopupDisabled = currentTeam && !currentTeam?.surveys_opt_in
- const [tab, setSurveyTab] = useState(SurveysTabs.All)
+ const [tab, setSurveyTab] = useState(SurveysTabs.Active)
const shouldShowEmptyState = !surveysLoading && surveys.length === 0
return (
-
+
@@ -84,10 +97,13 @@ export function Surveys(): JSX.Element {
/>
setSurveyTab(newTab)}
+ onChange={(newTab) => {
+ setSurveyTab(newTab)
+ setSurveysFilters({ ...filters, archived: newTab === SurveysTabs.Archived })
+ }}
tabs={[
- { key: SurveysTabs.All, label: 'All surveys' },
- { key: SurveysTabs.Archived, label: 'Archived surveys' },
+ { key: SurveysTabs.Active, label: 'Active' },
+ { key: SurveysTabs.Archived, label: 'Archived' },
]}
/>
{featureFlags[FEATURE_FLAGS.SURVEYS_SITE_APP_DEPRECATION] && (
@@ -111,25 +127,81 @@ export function Surveys(): JSX.Element {
) : null}
)}
- {surveysLoading ? (
-
- ) : (
- <>
- {(shouldShowEmptyState || !user?.has_seen_product_intro_for?.[ProductKey.SURVEYS]) && (
-
router.actions.push(urls.survey('new'))}
- isEmpty={surveys.length === 0}
- productKey={ProductKey.SURVEYS}
- />
- )}
- {!shouldShowEmptyState && (
+
+ <>
+ {(shouldShowEmptyState || !user?.has_seen_product_intro_for?.[ProductKey.SURVEYS]) && (
+ router.actions.push(urls.survey('new'))}
+ isEmpty={surveys.length === 0}
+ productKey={ProductKey.SURVEYS}
+ />
+ )}
+ {!shouldShowEmptyState && (
+ <>
+
+
+
+
+
+ Status
+
+ {
+ setSurveysFilters({ status })
+ }}
+ options={[
+ { label: 'Any', value: 'any' },
+ { label: 'Draft', value: 'draft' },
+ { label: 'Running', value: 'running' },
+ { label: 'Complete', value: 'complete' },
+ ]}
+ value={filters.status}
+ />
+
+ Created by
+
+ {
+ if (user) {
+ if (user === 'any') {
+ if (filters) {
+ const { created_by, ...restFilters } = filters
+ setSurveysFilters(restFilters, true)
+ }
+ } else {
+ setSurveysFilters({ created_by: user })
+ }
+ }
+ }}
+ options={uniqueCreators}
+ value={filters.created_by}
+ />
+
+
+
() as LemonTableColumn,
createdAtColumn() as LemonTableColumn,
@@ -280,18 +360,10 @@ export function Surveys(): JSX.Element {
},
},
]}
- dataSource={tab === SurveysTabs.Archived ? archivedSurveys : nonArchivedSurveys}
- defaultSorting={{
- columnKey: 'created_at',
- order: -1,
- }}
- nouns={['survey', 'surveys']}
- data-attr="surveys-table"
- emptyState="No surveys. Create a new survey?"
/>
- )}
- >
- )}
+ >
+ )}
+ >
)
}
diff --git a/frontend/src/scenes/surveys/constants.ts b/frontend/src/scenes/surveys/constants.ts
new file mode 100644
index 0000000000000..fa14c9310288c
--- /dev/null
+++ b/frontend/src/scenes/surveys/constants.ts
@@ -0,0 +1,137 @@
+import { FeatureFlagFilters, Survey, SurveyQuestionType, SurveyType } from '~/types'
+
+export const SURVEY_EVENT_NAME = 'survey sent'
+export const SURVEY_RESPONSE_PROPERTY = '$survey_response'
+
+export const SurveyQuestionLabel = {
+ [SurveyQuestionType.Open]: 'Open text',
+ [SurveyQuestionType.Rating]: 'Rating',
+ [SurveyQuestionType.Link]: 'Link',
+ [SurveyQuestionType.SingleChoice]: 'Single choice select',
+ [SurveyQuestionType.MultipleChoice]: 'Multiple choice select',
+}
+
+export const defaultSurveyAppearance = {
+ backgroundColor: 'white',
+ textColor: 'black',
+ submitButtonText: 'Submit',
+ submitButtonColor: '#2c2c2c',
+ ratingButtonColor: '#e0e2e8',
+ descriptionTextColor: '#4b4b52',
+ whiteLabel: false,
+ displayThankYouMessage: true,
+ placeholder: '',
+ position: 'right',
+ thankYouMessageHeader: 'Thank you for your feedback!',
+}
+
+export const defaultSurveyFieldValues = {
+ [SurveyQuestionType.Open]: {
+ questions: [
+ {
+ question: 'Give us feedback on our product!',
+ description: '',
+ },
+ ],
+ appearance: {
+ submitButtonText: 'Submit',
+ thankYouMessageHeader: 'Thank you for your feedback!',
+ },
+ },
+ [SurveyQuestionType.Link]: {
+ questions: [
+ {
+ question: 'Do you want to join our upcoming webinar?',
+ description: '',
+ },
+ ],
+ appearance: {
+ submitButtonText: 'Register',
+ thankYouMessageHeader: 'Redirecting ...',
+ },
+ },
+ [SurveyQuestionType.Rating]: {
+ questions: [
+ {
+ question: 'How likely are you to recommend us to a friend?',
+ description: '',
+ display: 'number',
+ scale: 10,
+ lowerBoundLabel: 'Unlikely',
+ upperBoundLabel: 'Very likely',
+ },
+ ],
+ appearance: {
+ thankYouMessageHeader: 'Thank you for your feedback!',
+ },
+ },
+ [SurveyQuestionType.SingleChoice]: {
+ questions: [
+ {
+ question: 'Have you found this tutorial useful?',
+ description: '',
+ choices: ['Yes', 'No'],
+ },
+ ],
+ appearance: {
+ submitButtonText: 'Submit',
+ thankYouMessageHeader: 'Thank you for your feedback!',
+ },
+ },
+ [SurveyQuestionType.MultipleChoice]: {
+ questions: [
+ {
+ question: 'Which types of content would you like to see more of?',
+ description: '',
+ choices: ['Tutorials', 'Customer case studies', 'Product announcements'],
+ },
+ ],
+ appearance: {
+ submitButtonText: 'Submit',
+ thankYouMessageHeader: 'Thank you for your feedback!',
+ },
+ },
+}
+
+export interface NewSurvey
+ extends Pick<
+ Survey,
+ | 'name'
+ | 'description'
+ | 'type'
+ | 'conditions'
+ | 'questions'
+ | 'start_date'
+ | 'end_date'
+ | 'linked_flag'
+ | 'targeting_flag'
+ | 'archived'
+ | 'appearance'
+ > {
+ id: 'new'
+ linked_flag_id: number | undefined
+ targeting_flag_filters: Pick | undefined
+}
+
+export const NEW_SURVEY: NewSurvey = {
+ id: 'new',
+ name: '',
+ description: '',
+ questions: [
+ {
+ type: SurveyQuestionType.Open,
+ question: defaultSurveyFieldValues[SurveyQuestionType.Open].questions[0].question,
+ description: defaultSurveyFieldValues[SurveyQuestionType.Open].questions[0].description,
+ },
+ ],
+ type: SurveyType.Popover,
+ linked_flag_id: undefined,
+ targeting_flag_filters: undefined,
+ linked_flag: null,
+ targeting_flag: null,
+ start_date: null,
+ end_date: null,
+ conditions: null,
+ archived: false,
+ appearance: defaultSurveyAppearance,
+}
diff --git a/frontend/src/scenes/surveys/surveyLogic.tsx b/frontend/src/scenes/surveys/surveyLogic.tsx
index b881f1e57b1ef..65e93c8c31956 100644
--- a/frontend/src/scenes/surveys/surveyLogic.tsx
+++ b/frontend/src/scenes/surveys/surveyLogic.tsx
@@ -8,7 +8,6 @@ import { urls } from 'scenes/urls'
import {
Breadcrumb,
ChartDisplayType,
- FeatureFlagFilters,
PluginType,
PropertyFilterType,
PropertyOperator,
@@ -26,135 +25,13 @@ import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import { featureFlagLogic } from 'scenes/feature-flags/featureFlagLogic'
import { featureFlagLogic as enabledFlagLogic } from 'lib/logic/featureFlagLogic'
import { FEATURE_FLAGS } from 'lib/constants'
-
-export interface NewSurvey
- extends Pick<
- Survey,
- | 'name'
- | 'description'
- | 'type'
- | 'conditions'
- | 'questions'
- | 'start_date'
- | 'end_date'
- | 'linked_flag'
- | 'targeting_flag'
- | 'archived'
- | 'appearance'
- > {
- id: 'new'
- linked_flag_id: number | undefined
- targeting_flag_filters: Pick | undefined
-}
-
-export const defaultSurveyAppearance = {
- backgroundColor: '#eeeded',
- submitButtonText: 'Submit',
- submitButtonColor: 'black',
- ratingButtonColor: 'white',
- ratingButtonActiveColor: 'black',
- borderColor: '#c9c6c6',
- placeholder: '',
- whiteLabel: false,
- displayThankYouMessage: true,
- thankYouMessageHeader: 'Thank you for your feedback!',
- position: 'right',
-}
-
-export const defaultSurveyFieldValues = {
- [SurveyQuestionType.Open]: {
- questions: [
- {
- question: 'Give us feedback on our product!',
- description: '',
- },
- ],
- appearance: {
- submitButtonText: 'Submit',
- thankYouMessageHeader: 'Thank you for your feedback!',
- },
- },
- [SurveyQuestionType.Link]: {
- questions: [
- {
- question: 'Do you want to join our upcoming webinar?',
- description: '',
- },
- ],
- appearance: {
- submitButtonText: 'Register',
- thankYouMessageHeader: 'Redirecting ...',
- },
- },
- [SurveyQuestionType.Rating]: {
- questions: [
- {
- question: 'How likely are you to recommend us to a friend?',
- description: '',
- display: 'number',
- scale: 10,
- lowerBoundLabel: 'Unlikely',
- upperBoundLabel: 'Very likely',
- },
- ],
- appearance: {
- thankYouMessageHeader: 'Thank you for your feedback!',
- },
- },
- [SurveyQuestionType.SingleChoice]: {
- questions: [
- {
- question: 'Have you found this tutorial useful?',
- description: '',
- choices: ['Yes', 'No'],
- },
- ],
- appearance: {
- submitButtonText: 'Submit',
- thankYouMessageHeader: 'Thank you for your feedback!',
- },
- },
- [SurveyQuestionType.MultipleChoice]: {
- questions: [
- {
- question: 'Which types of content would you like to see more of?',
- description: '',
- choices: ['Tutorials', 'Customer case studies', 'Product announcements'],
- },
- ],
- appearance: {
- submitButtonText: 'Submit',
- thankYouMessageHeader: 'Thank you for your feedback!',
- },
- },
-}
-
-export const NEW_SURVEY: NewSurvey = {
- id: 'new',
- name: '',
- description: '',
- questions: [
- {
- type: SurveyQuestionType.Open,
- question: defaultSurveyFieldValues[SurveyQuestionType.Open].questions[0].question,
- description: defaultSurveyFieldValues[SurveyQuestionType.Open].questions[0].description,
- },
- ],
- type: SurveyType.Popover,
- linked_flag_id: undefined,
- targeting_flag_filters: undefined,
- linked_flag: null,
- targeting_flag: null,
- start_date: null,
- end_date: null,
- conditions: null,
- archived: false,
- appearance: defaultSurveyAppearance,
-}
-
-export const surveyEventName = 'survey sent'
-
-const SURVEY_RESPONSE_PROPERTY = '$survey_response'
+import {
+ defaultSurveyFieldValues,
+ SURVEY_EVENT_NAME,
+ SURVEY_RESPONSE_PROPERTY,
+ NEW_SURVEY,
+ NewSurvey,
+} from './constants'
export interface SurveyLogicProps {
id: string | 'new'
@@ -443,7 +320,7 @@ export const surveyLogic = kea([
value: survey.id,
},
],
- series: [{ event: surveyEventName, kind: NodeKind.EventsNode }],
+ series: [{ event: SURVEY_EVENT_NAME, kind: NodeKind.EventsNode }],
trendsFilter: { display: ChartDisplayType.ActionsBarValue },
breakdown: { breakdown: '$survey_response', breakdown_type: 'event' },
},
diff --git a/frontend/src/scenes/surveys/surveysLogic.tsx b/frontend/src/scenes/surveys/surveysLogic.tsx
index 0fc81064f9619..fa25749343280 100644
--- a/frontend/src/scenes/surveys/surveysLogic.tsx
+++ b/frontend/src/scenes/surveys/surveysLogic.tsx
@@ -1,6 +1,7 @@
-import { afterMount, connect, kea, listeners, path, selectors } from 'kea'
+import { afterMount, connect, kea, listeners, path, selectors, actions, reducers } from 'kea'
import { loaders } from 'kea-loaders'
import api from 'lib/api'
+import Fuse from 'fuse.js'
import { AvailableFeature, Breadcrumb, ProgressStatus, Survey } from '~/types'
import { urls } from 'scenes/urls'
@@ -9,6 +10,7 @@ import { lemonToast } from '@posthog/lemon-ui'
import { userLogic } from 'scenes/userLogic'
import { router } from 'kea-router'
import { pluginsLogic } from 'scenes/plugins/pluginsLogic'
+import { LemonSelectOption } from 'lib/lemon-ui/LemonSelect'
export function getSurveyStatus(survey: Survey): ProgressStatus {
if (!survey.start_date) {
@@ -19,11 +21,25 @@ export function getSurveyStatus(survey: Survey): ProgressStatus {
return ProgressStatus.Complete
}
+export interface SurveysFilters {
+ status: string
+ created_by: string
+ archived: boolean
+}
+
+interface SurveysCreators {
+ [id: string]: string
+}
+
export const surveysLogic = kea([
path(['scenes', 'surveys', 'surveysLogic']),
connect(() => ({
values: [pluginsLogic, ['loading as pluginsLoading', 'enabledPlugins'], userLogic, ['user']],
})),
+ actions({
+ setSearchTerm: (searchTerm: string) => ({ searchTerm }),
+ setSurveysFilters: (filters: Partial, replace?: boolean) => ({ filters, replace }),
+ }),
loaders(({ values }) => ({
surveys: {
__default: [] as Survey[],
@@ -48,7 +64,24 @@ export const surveysLogic = kea([
},
},
})),
- listeners(() => ({
+ reducers({
+ searchTerm: {
+ setSearchTerm: (_, { searchTerm }) => searchTerm,
+ },
+ filters: [
+ {
+ archived: false,
+ status: 'any',
+ created_by: 'any',
+ } as Partial,
+ {
+ setSurveysFilters: (state, { filters }) => {
+ return { ...state, ...filters }
+ },
+ },
+ ],
+ }),
+ listeners(({ actions }) => ({
deleteSurveySuccess: () => {
lemonToast.success('Survey deleted')
router.actions.push(urls.surveys())
@@ -56,8 +89,49 @@ export const surveysLogic = kea([
updateSurveySuccess: () => {
lemonToast.success('Survey updated')
},
+ setSurveysFilters: () => {
+ actions.loadSurveys()
+ actions.loadResponsesCount()
+ },
})),
selectors({
+ searchedSurveys: [
+ (selectors) => [selectors.surveys, selectors.searchTerm, selectors.filters],
+ (surveys, searchTerm, filters) => {
+ let searchedSurveys = surveys
+
+ if (!searchTerm && Object.keys(filters).length === 0) {
+ return searchedSurveys
+ }
+
+ if (searchTerm) {
+ searchedSurveys = new Fuse(searchedSurveys, {
+ keys: ['key', 'name'],
+ threshold: 0.3,
+ })
+ .search(searchTerm)
+ .map((result) => result.item)
+ }
+
+ const { status, created_by, archived } = filters
+ if (status !== 'any') {
+ searchedSurveys = searchedSurveys.filter((survey) => getSurveyStatus(survey) === status)
+ }
+ if (created_by !== 'any') {
+ searchedSurveys = searchedSurveys.filter(
+ (survey) => survey.created_by?.id === (created_by ? parseInt(created_by) : '')
+ )
+ }
+
+ if (archived) {
+ searchedSurveys = searchedSurveys.filter((survey) => survey.archived)
+ } else {
+ searchedSurveys = searchedSurveys.filter((survey) => !survey.archived)
+ }
+
+ return searchedSurveys
+ },
+ ],
breadcrumbs: [
() => [],
(): Breadcrumb[] => [
@@ -67,13 +141,23 @@ export const surveysLogic = kea([
},
],
],
- nonArchivedSurveys: [
- (s) => [s.surveys],
- (surveys: Survey[]): Survey[] => surveys.filter((survey) => !survey.archived),
- ],
- archivedSurveys: [
- (s) => [s.surveys],
- (surveys: Survey[]): Survey[] => surveys.filter((survey) => survey.archived),
+ uniqueCreators: [
+ (selectors) => [selectors.surveys],
+ (surveys) => {
+ const creators: SurveysCreators = {}
+ for (const survey of surveys) {
+ if (survey.created_by) {
+ if (!creators[survey.created_by.id]) {
+ creators[survey.created_by.id] = survey.created_by.first_name
+ }
+ }
+ }
+ const response: LemonSelectOption[] = [
+ { label: 'Any user', value: 'any' },
+ ...Object.entries(creators).map(([id, first_name]) => ({ label: first_name, value: id })),
+ ]
+ return response
+ },
],
whitelabelAvailable: [
(s) => [s.user],
@@ -86,8 +170,8 @@ export const surveysLogic = kea([
},
],
}),
- afterMount(async ({ actions }) => {
- await actions.loadSurveys()
- await actions.loadResponsesCount()
+ afterMount(({ actions }) => {
+ actions.loadSurveys()
+ actions.loadResponsesCount()
}),
])