diff --git a/cypress/e2e/surveys.cy.ts b/cypress/e2e/surveys.cy.ts index 55a87ddbffe60..3664ec86b1cf7 100644 --- a/cypress/e2e/surveys.cy.ts +++ b/cypress/e2e/surveys.cy.ts @@ -78,12 +78,11 @@ describe('Surveys', () => { .should('include', '1 - 5') // make sure the preview is updated - cy.get('[data-attr="survey-preview"]') - .find('form') + cy.get('[class="survey-form"]') .should('contain', 'How likely are you to recommend us to a friend?') .should('contain', 'Unlikely') .should('contain', 'Very likely') - cy.get('[data-attr="survey-preview"]').find('form').find('.ratings-number').should('have.length', 5) + cy.get('[class="survey-form"]').find('.ratings-number').should('have.length', 5) // add targeting filters cy.get('.LemonCollapsePanel').contains('Targeting').click() @@ -168,60 +167,6 @@ describe('Surveys', () => { cy.get('.Toastify__toast-body').contains('Survey deleted').should('be.visible') }) - it('creates a new multiple choice survey with an open-ended choice', () => { - cy.get('h1').should('contain', 'Surveys') - cy.get('[data-attr=new-survey]').click() - cy.get('[data-attr=new-blank-survey]').click() - - // add a multiple choice question with an open-ended question - cy.get('[data-attr=survey-name]').focus().type(name).should('have.value', name) - cy.get('[data-attr="survey-question-type-0"]').click() - cy.contains('Multiple choice select').click() - cy.get('button').contains('Add open-ended choice').click() - - // check default open-ended choice form input and appearance after - // open-ended choice was added - cy.get('.LemonInput__input[value="Other"]') - cy.get('.choice-option').eq(3).contains('Other:') - cy.get('.choice-option').eq(3).find('input[type="text"]').should('have.value', '') - - // typing in open-ended question's appearance automatically checks the - // checkbox - cy.get('.choice-option').eq(3).find('input[type="checkbox"]').should('not.be.checked') - cy.get('.choice-option').eq(3).find('input[type="text"]').type('Outreach') - cy.get('.choice-option').eq(3).find('input[type="checkbox"]').should('be.checked') - - // clicking on open-ended question's appearance label unchecks or checks - // the checkbox - cy.get('.choice-option').eq(3).click() - cy.get('.choice-option').eq(3).find('input[type="checkbox"]').should('not.be.checked') - cy.get('.choice-option').eq(3).click() - cy.get('.choice-option').eq(3).find('input[type="checkbox"]').should('be.checked') - - // removing text in open-ended question's appearance automatically - // unchecks the checkbox - cy.get('.choice-option').eq(3).find('input[type="text"]').clear() - - // open-ended question label doesn't change even if appearance input - // changes - cy.get('.LemonInput__input[value="Other"]') - - // change open-ended choice after the label was added - cy.contains('Choices').parent().find('input[type="text"]').eq(3).clear() - cy.contains('Choices').parent().find('input[type="text"]').eq(3).type('First Choice') - cy.get('.choice-option').eq(3).contains('First Choice:') - - // attempt to create and save survey - cy.get('[data-attr=save-survey]').first().click() - - // after save there should be a launch button - cy.get('button[data-attr="launch-survey"]').should('have.text', 'Launch') - - cy.clickNavMenu('surveys') - cy.get('[data-attr=surveys-table]').should('contain', name) - cy.get(`[data-row-key="${name}"]`).contains(name).click() - }) - it('duplicates a survey', () => { // create survey cy.get('[data-attr=new-survey]').click() diff --git a/frontend/__snapshots__/components-compact-list--compact-list--dark.png b/frontend/__snapshots__/components-compact-list--compact-list--dark.png index 688c0cfdbddc3..0c254a8d1a325 100644 Binary files a/frontend/__snapshots__/components-compact-list--compact-list--dark.png and b/frontend/__snapshots__/components-compact-list--compact-list--dark.png differ diff --git a/frontend/__snapshots__/components-compact-list--compact-list--light.png b/frontend/__snapshots__/components-compact-list--compact-list--light.png index 6fe382c462e4f..3d9c8f8536de7 100644 Binary files a/frontend/__snapshots__/components-compact-list--compact-list--light.png and b/frontend/__snapshots__/components-compact-list--compact-list--light.png differ diff --git a/frontend/__snapshots__/components-empty-message--empty-message--dark.png b/frontend/__snapshots__/components-empty-message--empty-message--dark.png index 5bf720047b592..a20be98f9c4cf 100644 Binary files a/frontend/__snapshots__/components-empty-message--empty-message--dark.png and b/frontend/__snapshots__/components-empty-message--empty-message--dark.png differ diff --git a/frontend/__snapshots__/components-empty-message--empty-message--light.png b/frontend/__snapshots__/components-empty-message--empty-message--light.png index fbd6c235ce79f..4be1aa77dfc4e 100644 Binary files a/frontend/__snapshots__/components-empty-message--empty-message--light.png and b/frontend/__snapshots__/components-empty-message--empty-message--light.png differ diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation-3000--dark.png b/frontend/__snapshots__/posthog-3000-navigation--navigation-3000--dark.png index 5c779da84263d..b36cb6e8a9310 100644 Binary files a/frontend/__snapshots__/posthog-3000-navigation--navigation-3000--dark.png and b/frontend/__snapshots__/posthog-3000-navigation--navigation-3000--dark.png differ diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation-3000--light.png b/frontend/__snapshots__/posthog-3000-navigation--navigation-3000--light.png index f85e6f311abc2..c4c96af5ce1a7 100644 Binary files a/frontend/__snapshots__/posthog-3000-navigation--navigation-3000--light.png and b/frontend/__snapshots__/posthog-3000-navigation--navigation-3000--light.png differ diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation-base--dark.png b/frontend/__snapshots__/posthog-3000-navigation--navigation-base--dark.png index 06adea217229e..6cd9db9354e47 100644 Binary files a/frontend/__snapshots__/posthog-3000-navigation--navigation-base--dark.png and b/frontend/__snapshots__/posthog-3000-navigation--navigation-base--dark.png differ diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation-base--light.png b/frontend/__snapshots__/posthog-3000-navigation--navigation-base--light.png index d1bd6fb608eaa..0c4a0a9c98b9e 100644 Binary files a/frontend/__snapshots__/posthog-3000-navigation--navigation-base--light.png and b/frontend/__snapshots__/posthog-3000-navigation--navigation-base--light.png differ diff --git a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist--dark.png b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist--dark.png index 54b5fe58b05f5..7dbaf6ab7fea4 100644 Binary files a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist--dark.png and b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist--light.png b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist--light.png index 6588de25fb805..10c2fe114e7d6 100644 Binary files a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist--light.png and b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist--light.png differ diff --git a/frontend/__snapshots__/scenes-app-project-homepage--project-homepage--dark.png b/frontend/__snapshots__/scenes-app-project-homepage--project-homepage--dark.png index 4653016c30cb8..8bec7a37db054 100644 Binary files a/frontend/__snapshots__/scenes-app-project-homepage--project-homepage--dark.png and b/frontend/__snapshots__/scenes-app-project-homepage--project-homepage--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-project-homepage--project-homepage--light.png b/frontend/__snapshots__/scenes-app-project-homepage--project-homepage--light.png index 5941995842f24..d6282aaf33a1a 100644 Binary files a/frontend/__snapshots__/scenes-app-project-homepage--project-homepage--light.png and b/frontend/__snapshots__/scenes-app-project-homepage--project-homepage--light.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey--dark.png b/frontend/__snapshots__/scenes-app-surveys--new-survey--dark.png index c891cc11c1495..b489889fadece 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey--dark.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey--light.png b/frontend/__snapshots__/scenes-app-surveys--new-survey--light.png index 03107f4105ab8..816d2f3a35754 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey--light.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey--light.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey-appearance-section--dark.png b/frontend/__snapshots__/scenes-app-surveys--new-survey-appearance-section--dark.png index 73fcf46c2537a..5368b21ef1900 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey-appearance-section--dark.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey-appearance-section--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey-appearance-section--light.png b/frontend/__snapshots__/scenes-app-surveys--new-survey-appearance-section--light.png index 3720fb3b2f2ce..251f21122ed4a 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey-appearance-section--light.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey-appearance-section--light.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey-customisation-section--dark.png b/frontend/__snapshots__/scenes-app-surveys--new-survey-customisation-section--dark.png index bbb49aee27975..b34e09d93cb9d 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey-customisation-section--dark.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey-customisation-section--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey-customisation-section--light.png b/frontend/__snapshots__/scenes-app-surveys--new-survey-customisation-section--light.png index 35d4ffbea5e2a..0bf882225f1fc 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey-customisation-section--light.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey-customisation-section--light.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey-presentation-section--dark.png b/frontend/__snapshots__/scenes-app-surveys--new-survey-presentation-section--dark.png index 2979dd4f45bff..4eedbc3b1b729 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey-presentation-section--dark.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey-presentation-section--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey-presentation-section--light.png b/frontend/__snapshots__/scenes-app-surveys--new-survey-presentation-section--light.png index 098a7d1a35d6d..cff11fd6f5ada 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey-presentation-section--light.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey-presentation-section--light.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey-targeting-section--dark.png b/frontend/__snapshots__/scenes-app-surveys--new-survey-targeting-section--dark.png index 49f611b6e5f06..5b72397154674 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey-targeting-section--dark.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey-targeting-section--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--new-survey-targeting-section--light.png b/frontend/__snapshots__/scenes-app-surveys--new-survey-targeting-section--light.png index 25c9dc6e9f764..4b568be22563c 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--new-survey-targeting-section--light.png and b/frontend/__snapshots__/scenes-app-surveys--new-survey-targeting-section--light.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--survey-templates--dark.png b/frontend/__snapshots__/scenes-app-surveys--survey-templates--dark.png index 730cf1d480898..4bbb750584df6 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--survey-templates--dark.png and b/frontend/__snapshots__/scenes-app-surveys--survey-templates--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-surveys--survey-templates--light.png b/frontend/__snapshots__/scenes-app-surveys--survey-templates--light.png index 9487421c71b71..48af4ff8e5bf0 100644 Binary files a/frontend/__snapshots__/scenes-app-surveys--survey-templates--light.png and b/frontend/__snapshots__/scenes-app-surveys--survey-templates--light.png differ diff --git a/frontend/src/@types/survey-preview.d.ts b/frontend/src/@types/survey-preview.d.ts new file mode 100644 index 0000000000000..bd771ced9772d --- /dev/null +++ b/frontend/src/@types/survey-preview.d.ts @@ -0,0 +1 @@ +declare module 'posthog-js/dist/surveys-module-previews' diff --git a/frontend/src/lib/utils.tsx b/frontend/src/lib/utils.tsx index 20b8114375939..e4b859c76fa3a 100644 --- a/frontend/src/lib/utils.tsx +++ b/frontend/src/lib/utils.tsx @@ -417,9 +417,8 @@ export function humanFriendlyLargeNumber(d: number): string { } else if (!isFinite(d)) { if (d > 0) { return 'inf' - } else { - return '-inf' } + return '-inf' } const trillion = 1_000_000_000_000 const billion = 1_000_000_000 @@ -443,9 +442,8 @@ export function humanFriendlyLargeNumber(d: number): string { } if (d >= thousand) { return `${prefix}${(d / thousand).toString()}K` - } else { - return `${prefix}${d}` } + return `${prefix}${d}` } export const humanFriendlyMilliseconds = (timestamp: number | undefined): string | undefined => { @@ -552,10 +550,9 @@ export function colonDelimitedDuration(d: string | number | null | undefined, fi ;[weeks, days, h, m, s].forEach((unit, i) => { if (!fixedUnits && !unit && !stopTrimming && i < 3) { return - } else { - units.push(zeroPad(unit, 2)) - stopTrimming = true } + units.push(zeroPad(unit, 2)) + stopTrimming = true }) if (fixedUnits) { @@ -600,10 +597,9 @@ export function isDomain(url: string): boolean { const parsedUrl = new URL(url) if (parsedUrl.protocol.includes('http') && (!parsedUrl.pathname || parsedUrl.pathname === '/')) { return true - } else { - if (!parsedUrl.pathname.replace(/^\/\//, '').includes('/')) { - return true - } + } + if (!parsedUrl.pathname.replace(/^\/\//, '').includes('/')) { + return true } } catch { return false @@ -700,10 +696,9 @@ export function autoCaptureEventToDescription( if (shortForm) { return [getVerb(), getValue() ?? getTag()].filter((x) => x).join(' ') - } else { - const value = getValue() - return [getVerb(), getTag(), value].filter((x) => x).join(' ') } + const value = getValue() + return [getVerb(), getTag(), value].filter((x) => x).join(' ') } export function determineDifferenceType( @@ -722,9 +717,8 @@ export function determineDifferenceType( return 'day' } else if (first.diff(second, 'hours') !== 0) { return 'hour' - } else { - return 'minute' } + return 'minute' } const DATE_FORMAT = 'MMMM D, YYYY' @@ -872,9 +866,8 @@ export function dateFilterToText( return isDateFormatted ? formatDateRange(dayjs(dateFrom), dayjs()) : `Last ${days} days` } else if (days === 0) { return isDateFormatted ? dayjs(dateFrom).format(dateFormat) : `Today` - } else { - return isDateFormatted ? `${dayjs(dateFrom).format(dateFormat)} - ` : `Starting from ${dateFrom}` } + return isDateFormatted ? `${dayjs(dateFrom).format(dateFormat)} - ` : `Starting from ${dateFrom}` } for (const { key, values, getFormattedDate } of dateOptions) { @@ -912,9 +905,8 @@ export function dateFilterToText( return formatDateRange(date, dayjs().endOf('d')) } else if (startOfRange) { return formatDate(date, dateFormat) - } else { - return `Last ${counter} ${dateOption}${counter > 1 ? 's' : ''}` } + return `Last ${counter} ${dateOption}${counter > 1 ? 's' : ''}` } } diff --git a/frontend/src/queries/nodes/DataTable/DataTable.tsx b/frontend/src/queries/nodes/DataTable/DataTable.tsx index f0174514a1a47..ea46f7a556b08 100644 --- a/frontend/src/queries/nodes/DataTable/DataTable.tsx +++ b/frontend/src/queries/nodes/DataTable/DataTable.tsx @@ -171,9 +171,8 @@ export function DataTable({ children: label, props: { colSpan: columnsInLemonTable.length + (eventActionsColumnShown ? 1 : 0) }, } - } else { - return { props: { colSpan: 0 } } } + return { props: { colSpan: 0 } } } else if (result) { if (sourceFeatures.has(QueryFeature.resultIsArrayOfArrays)) { return renderColumn(key, result[index], result, query, setQuery, context) diff --git a/frontend/src/scenes/dashboard/dashboardLogic.tsx b/frontend/src/scenes/dashboard/dashboardLogic.tsx index d7ac51dd3cd0c..733bfdf894686 100644 --- a/frontend/src/scenes/dashboard/dashboardLogic.tsx +++ b/frontend/src/scenes/dashboard/dashboardLogic.tsx @@ -259,15 +259,14 @@ export const dashboardLogic = kea([ if (fromDashboard !== props.id) { return values.dashboard - } else { - return await api.update( - `api/projects/${teamLogic.values.currentTeamId}/dashboards/${props.id}/move_tile`, - { - tile, - toDashboard, - } - ) } + return await api.update( + `api/projects/${teamLogic.values.currentTeamId}/dashboards/${props.id}/move_tile`, + { + tile, + toDashboard, + } + ) }, }, ], @@ -704,9 +703,8 @@ export const dashboardLogic = kea([ return -1 } else if (ay > by || (ay == by && ax > bx)) { return 1 - } else { - return 0 } + return 0 }) }, ], diff --git a/frontend/src/scenes/feature-flags/FeatureFlag.tsx b/frontend/src/scenes/feature-flags/FeatureFlag.tsx index f202471bbb5ad..70a94f7faa654 100644 --- a/frontend/src/scenes/feature-flags/FeatureFlag.tsx +++ b/frontend/src/scenes/feature-flags/FeatureFlag.tsx @@ -708,9 +708,8 @@ function UsageTab({ featureFlag }: { id: string; featureFlag: FeatureFlagType }) function variantConcatWithPunctuation(phrases: string[]): string { if (phrases === null || phrases.length < 3) { return concatWithPunctuation(phrases) - } else { - return `${phrases[0]} and ${phrases.length - 1} more sets` } + return `${phrases[0]} and ${phrases.length - 1} more sets` } function FeatureFlagRollout({ readOnly }: { readOnly?: boolean }): JSX.Element { diff --git a/frontend/src/scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow.tsx b/frontend/src/scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow.tsx index f544e601e506d..32846140246b4 100644 --- a/frontend/src/scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow.tsx +++ b/frontend/src/scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow.tsx @@ -72,9 +72,8 @@ const getValue = ( return 'All events' } else if (filter.type === 'actions') { return typeof value === 'string' ? parseInt(value) : value || undefined - } else { - return value === null ? null : value || undefined } + return value === null ? null : value || undefined } export interface ActionFilterRowProps { diff --git a/frontend/src/scenes/insights/utils.tsx b/frontend/src/scenes/insights/utils.tsx index 2ba3b5dca932e..b83dd51ba9f46 100644 --- a/frontend/src/scenes/insights/utils.tsx +++ b/frontend/src/scenes/insights/utils.tsx @@ -264,17 +264,15 @@ export function formatBreakdownLabel( formatBreakdownLabel(cohorts, formatPropertyValueForDisplay, v, breakdown, breakdown_type, isHistogram) ) .join('::') - } else { - return '' } + return '' } export function formatBreakdownType(breakdownFilter: BreakdownFilter): string { if (breakdownFilter.breakdown_type === 'cohort') { return 'Cohort' - } else { - return breakdownFilter?.breakdown?.toString() || 'Breakdown Value' } + return breakdownFilter?.breakdown?.toString() || 'Breakdown Value' } export function sortDates(dates: Array): Array { @@ -313,9 +311,8 @@ export function concatWithPunctuation(phrases: string[]): string { return phrases[0] } else if (phrases.length === 2) { return `${phrases[0]} and ${phrases[1]}` - } else { - return `${phrases.slice(0, phrases.length - 1).join(', ')}, and ${phrases[phrases.length - 1]}` } + return `${phrases.slice(0, phrases.length - 1).join(', ')}, and ${phrases[phrases.length - 1]}` } export function insightUrlForEvent(event: Pick): string | undefined { diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx index e57f5a40766fb..e908df8009e74 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx @@ -9,13 +9,12 @@ import { notebookNodeLogic } from './notebookNodeLogic' import { JSONContent, NotebookNodeProps } from '../Notebook/utils' import { buildFlagContent } from './NotebookNodeFlag' 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' import { SurveyReleaseSummary } from 'scenes/surveys/Survey' import { useEffect } from 'react' import { NotFound } from 'lib/components/NotFound' +import { SurveyAppearancePreview } from 'scenes/surveys/SurveyAppearancePreview' const Component = ({ attributes }: NotebookNodeProps): JSX.Element => { const { id } = attributes @@ -81,10 +80,10 @@ const Component = ({ attributes }: NotebookNodeProps
-
diff --git a/frontend/src/scenes/surveys/SurveyAppearance.scss b/frontend/src/scenes/surveys/SurveyAppearance.scss deleted file mode 100644 index 1ac9aca5439e6..0000000000000 --- a/frontend/src/scenes/surveys/SurveyAppearance.scss +++ /dev/null @@ -1,332 +0,0 @@ -.survey-form { - position: relative; - box-sizing: border-box; - flex-direction: column; - width: 320px; - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, - 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; - font-weight: normal; - line-height: 1.4; - color: black; - text-align: left; - border-bottom: 0; - border-radius: 10px; - box-shadow: -6px 0 16px -8px rgb(0 0 0 / 8%), -9px 0 28px 0 rgb(0 0 0 / 5%), -12px 0 48px 16px rgb(0 0 0 / 3%); -} - -.form-submit[disabled] { - cursor: not-allowed; - filter: grayscale(100%); - opacity: 0.6; -} - -.survey-form textarea { - padding-top: 10px; - padding-right: 10px; - padding-left: 10px; - margin-top: 14px; - font-family: -apple-system, BlinkMacSystemFont, Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, - 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; - font-size: 14px; - color: black; - background: white; - border-radius: var(--radius); - outline: none; -} - -.form-submit { - position: relative; - box-sizing: border-box; - display: inline-block; - width: 100%; - padding: 12px; - margin: 0; - overflow: visible; - font-family: inherit; - font-size: 14px; - font-weight: 700; - text-align: center; - text-shadow: 0 -1px 0 rgb(0 0 0 / 12%); - text-transform: none; - white-space: nowrap; - touch-action: manipulation; - cursor: pointer; - user-select: none; - border: 1.5px solid transparent; - border-radius: var(--radius); - outline: 0; - box-shadow: 0 2px 0 rgb(0 0 0 / 4.5%); -} - -.form-cancel { - float: right; - cursor: pointer; - background: none; - border: none; -} - -.cancel-btn-wrapper { - position: absolute; - top: 0; - right: 0; - display: flex; - align-items: center; - justify-content: center; - width: 35px; - height: 35px; - background: white; - border-radius: 100%; - transform: translate(50%, -50%); -} - -.bolded { - font-weight: 600; -} - -.buttons { - display: flex; - justify-content: center; -} - -.footer-branding { - display: flex; - gap: 4px; - align-items: center; - justify-content: center; - margin-top: 10px; - font-size: 11px; - font-weight: 500; - color: inherit !important; - text-align: center; - text-decoration: none; -} - -.survey-box { - display: flex; - flex-direction: column; - padding: 20px 25px 10px; -} - -.survey-question { - font-size: 14px; - font-weight: 500; -} - -.question-textarea-wrapper { - display: flex; - flex-direction: column; -} - -.description { - margin-top: 5px; - font-size: 13px; - color: rgba(var(--survey-text-color), 0.6); - - a { - color: rgb(var(--survey-text-color)); - - &:hover { - color: rgba(var(--survey-text-color), 0.6); - } - } -} - -.ratings-number { - padding: 8px 0; - font-size: 14px; - border: none; -} - -.ratings-number:hover { - cursor: pointer; -} - -.rating-options { - margin-top: 14px; -} - -.rating-options-buttons { - display: grid; - overflow: hidden; - border-radius: var(--radius); -} - -.rating-options-buttons > .ratings-number { - border-right: 1px solid; -} - -.rating-options-buttons > .ratings-number:last-of-type { - border-right: 0 !important; -} - -.rating-options-emoji { - display: flex; - justify-content: space-between; -} - -.ratings-emoji { - padding: 0; - font-size: 16px; - background-color: transparent; - border: none; -} - -.ratings-emoji:hover { - cursor: pointer; -} - -.rating-text { - display: flex; - flex-direction: row; - justify-content: space-between; - margin-top: 6px; - font-size: 11px; - opacity: 0.6; -} - -.multiple-choice-options { - margin-top: 13px; - font-size: 14px; - color: black; -} - -.multiple-choice-options .choice-option { - position: relative; - display: flex; - gap: 4px; - align-items: center; - margin-bottom: 5px; - font-size: 13px; - cursor: pointer; -} - -.multiple-choice-options > .choice-option:last-of-type { - margin-bottom: 0; -} - -.multiple-choice-options input { - position: absolute; - inset: 0; - width: 100%; - height: 100%; - cursor: pointer; - opacity: 0; -} - -.choice-check { - position: absolute; - right: 10px; - background: white; -} - -.choice-check svg { - display: none; -} - -.multiple-choice-options .choice-option:hover .choice-check svg { - display: inline-block; - opacity: 0.25; -} - -.multiple-choice-options input:checked + label + .choice-check svg { - display: inline-block; - opacity: 1 !important; -} - -.multiple-choice-options input:checked + label { - font-weight: bold; - border: 1.5px solid rgb(0 0 0 / 100%); -} - -.multiple-choice-options input:checked + label input { - font-weight: bold; -} - -.multiple-choice-options label { - width: 100%; - padding: 10px; - cursor: pointer; - background: white; - border: 1.5px solid rgb(0 0 0 / 25%); - border-radius: var(--radius); -} - -.multiple-choice-options .choice-option-open label { - display: flex; - flex-wrap: wrap; - gap: 8px; - max-width: 100%; - padding-right: 30px; -} - -.multiple-choice-options .choice-option-open input:disabled + label { - opacity: 0.6; -} - -.multiple-choice-options .choice-option-open label input { - position: relative; - flex-grow: 1; - border: 0; - outline: 0; - opacity: 1; -} - -.thank-you-message { - position: relative; - bottom: 0; - box-sizing: border-box; - width: 320px; - min-width: 150px; - padding: 20px 25px 10px; - font-family: -apple-system, BlinkMacSystemFont, Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, - 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; - line-height: 1.4; - text-align: center; - border-radius: 10px; - box-shadow: -6px 0 16px -8px rgb(0 0 0 / 8%), -9px 0 28px 0 rgb(0 0 0 / 5%), -12px 0 48px 16px rgb(0 0 0 / 3%); -} - -.thank-you-message-body { - margin-top: 6px; - font-size: 14px; -} - -.thank-you-message-header { - margin: 10px 0 0; - font-size: 19px; - font-weight: bold; - color: inherit; -} - -.thank-you-message-container .form-submit { - margin-top: 20px; - margin-bottom: 10px; -} - -.thank-you-message-countdown { - margin-left: 6px; -} - -.bottom-section { - margin-top: 14px; -} - -.ph-survey-widget-tab { - position: fixed; - top: 50%; - right: 0; - z-index: 9999999; - min-width: 40px; - padding: 8px 12px; - font-weight: 500; - text-align: center; - cursor: pointer; - border-radius: 3px 3px 0 0; - transform: rotate(-90deg) translate(0, -100%); - transform-origin: right top; -} - -.ph-survey-widget-tab:hover { - padding-bottom: 13px; -} diff --git a/frontend/src/scenes/surveys/SurveyAppearance.tsx b/frontend/src/scenes/surveys/SurveyAppearance.tsx deleted file mode 100644 index 750b880f7d28c..0000000000000 --- a/frontend/src/scenes/surveys/SurveyAppearance.tsx +++ /dev/null @@ -1,900 +0,0 @@ -import './SurveyAppearance.scss' - -import { LemonButton, LemonCheckbox, LemonInput, LemonSelect, Link } from '@posthog/lemon-ui' -import { useValues } from 'kea' -import { PayGateMini } from 'lib/components/PayGateMini/PayGateMini' -import { upgradeModalLogic } from 'lib/components/UpgradeModal/upgradeModalLogic' -import React, { useEffect, useRef, useState } from 'react' - -import { - AvailableFeature, - BasicSurveyQuestion, - LinkSurveyQuestion, - MultipleSurveyQuestion, - RatingSurveyQuestion, - SurveyAppearance as SurveyAppearanceType, - SurveyQuestion, - SurveyQuestionType, - SurveyType, -} from '~/types' - -import { defaultSurveyAppearance } from './constants' -import { - cancel, - check, - dissatisfiedEmoji, - getTextColor, - getTextColorComponents, - neutralEmoji, - posthogLogoSVG, - satisfiedEmoji, - veryDissatisfiedEmoji, - verySatisfiedEmoji, -} from './SurveyAppearanceUtils' -import { surveysLogic } from './surveysLogic' -import { sanitizeHTML } from './utils' - -interface SurveyAppearanceProps { - surveyType: SurveyType - appearance: SurveyAppearanceType - surveyQuestionItem: SurveyQuestion - preview?: boolean - isEditingSurvey?: boolean -} - -interface CustomizationProps { - appearance: SurveyAppearanceType - surveyQuestionItem: RatingSurveyQuestion | SurveyQuestion | MultipleSurveyQuestion - onAppearanceChange: (appearance: SurveyAppearanceType) => void -} - -interface WidgetCustomizationProps extends Omit {} - -interface ButtonProps { - link?: string | null - type?: SurveyQuestionType - onSubmit: () => void - appearance: SurveyAppearanceType - children: React.ReactNode -} - -const SurveyButton = ({ - link, - type, - onSubmit, - appearance, - children, - ...other -}: ButtonProps & React.HTMLProps): JSX.Element => { - const [textColor, setTextColor] = useState('black') - const ref = useRef(null) - - useEffect(() => { - if (ref.current) { - const textColor = getTextColor(ref.current) - setTextColor(textColor) - } - }, [appearance.submitButtonColor]) - - return ( - - ) -} - -export function SurveyAppearance({ - surveyType, - appearance, - surveyQuestionItem, - preview, - isEditingSurvey, -}: SurveyAppearanceProps): JSX.Element { - return ( -
- {!preview && isEditingSurvey && surveyType === SurveyType.Widget && appearance.widgetType === 'tab' && ( - - )} - {surveyQuestionItem.type === SurveyQuestionType.Rating && ( - undefined} - /> - )} - {(surveyQuestionItem.type === SurveyQuestionType.SingleChoice || - surveyQuestionItem.type === SurveyQuestionType.MultipleChoice) && ( - undefined} - /> - )} - {(surveyQuestionItem.type === SurveyQuestionType.Open || - surveyQuestionItem.type === SurveyQuestionType.Link) && ( - undefined} - /> - )} -
- ) -} - -export function Customization({ appearance, surveyQuestionItem, onAppearanceChange }: CustomizationProps): JSX.Element { - const { surveysStylingAvailable } = useValues(surveysLogic) - const { guardAvailableFeature } = useValues(upgradeModalLogic) - return ( - <> -
- {!surveysStylingAvailable && ( - - <> - - )} -
Background color
- onAppearanceChange({ ...appearance, backgroundColor })} - disabled={!surveysStylingAvailable} - /> -
Border color
- onAppearanceChange({ ...appearance, borderColor })} - disabled={!surveysStylingAvailable} - /> - <> -
Position
-
- {['left', 'center', 'right'].map((position) => { - return ( - onAppearanceChange({ ...appearance, position })} - active={appearance.position === position} - disabledReason={ - surveysStylingAvailable - ? null - : 'Subscribe to surveys to customize survey position.' - } - > - {position} - - ) - })} -
- - {surveyQuestionItem.type === SurveyQuestionType.Rating && ( - <> -
Rating button color
- onAppearanceChange({ ...appearance, ratingButtonColor })} - disabled={!surveysStylingAvailable} - /> -
Rating button active color
- - onAppearanceChange({ ...appearance, ratingButtonActiveColor }) - } - disabled={!surveysStylingAvailable} - /> - - )} -
Button color
- onAppearanceChange({ ...appearance, submitButtonColor })} - disabled={!surveysStylingAvailable} - /> - {surveyQuestionItem.type === SurveyQuestionType.Open && ( - <> -
Placeholder
- onAppearanceChange({ ...appearance, placeholder })} - disabled={!surveysStylingAvailable} - /> - - )} -
- - Hide PostHog branding -
- } - onChange={(checked) => - guardAvailableFeature(AvailableFeature.WHITE_LABELLING, () => - onAppearanceChange({ ...appearance, whiteLabel: checked }) - ) - } - checked={appearance?.whiteLabel} - /> -
- - - ) -} - -export function WidgetCustomization({ appearance, onAppearanceChange }: WidgetCustomizationProps): JSX.Element { - return ( - <> -
Feedback button type
- onAppearanceChange({ ...appearance, widgetType })} - options={[ - { label: 'Embedded tab', value: 'tab' }, - { label: 'Custom', value: 'selector' }, - ]} - /> - {appearance.widgetType === 'selector' ? ( - <> -
Class or ID selector
- onAppearanceChange({ ...appearance, widgetSelector })} - placeholder="ex: .feedback-button, #feedback-button" - /> - - ) : ( - <> -
Label
- onAppearanceChange({ ...appearance, widgetLabel })} - /> -
Background color
- onAppearanceChange({ ...appearance, widgetColor })} - placeholder="#e0a045" - /> - - )} - - ) -} - -// This should be synced to the UI of the surveys app plugin -export function BaseAppearance({ - question, - appearance, - onSubmit, - preview, - isWidgetSurvey, -}: { - question: BasicSurveyQuestion | LinkSurveyQuestion - appearance: SurveyAppearanceType - onSubmit: () => void - preview?: boolean - isWidgetSurvey?: boolean -}): JSX.Element { - const [textColor, setTextColor] = useState<'white' | 'black'>('black') - const ref = useRef(null) - - useEffect(() => { - if (ref.current) { - const textColor = getTextColor(ref.current) - setTextColor(textColor) - } - }, [appearance.backgroundColor]) - - return ( -
-
- {!preview && ( -
- -
- )} -
-
- {/* 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 */} - {question.description && ( -
- )} - {question.type === SurveyQuestionType.Open && ( -