diff --git a/assets/js/dashboard/stats/behaviours/index.js b/assets/js/dashboard/stats/behaviours/index.js
index 8ffca74f1624..c611b3bb35b7 100644
--- a/assets/js/dashboard/stats/behaviours/index.js
+++ b/assets/js/dashboard/stats/behaviours/index.js
@@ -3,6 +3,11 @@ import * as storage from '../../util/storage'
import ImportedQueryUnsupportedWarning from '../imported-query-unsupported-warning'
import Properties from './props'
import { FeatureSetupNotice } from '../../components/feature-setup-notice'
+import {
+ ExplorationPreviewMock,
+ FunnelsPreviewMock,
+ PropertiesPreviewMock
+} from '../../components/feature-preview-mocks'
import {
hasConversionGoalFilter,
getGoalFilter,
@@ -32,7 +37,7 @@ import { getSpecialGoal, isPageViewGoal, isSpecialGoal } from '../../util/goals'
/*global BUILD_EXTRA*/
/*global require*/
-function maybeRequire() {
+function maybeRequireFunnels() {
if (BUILD_EXTRA) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('../../extra/funnel')
@@ -46,12 +51,12 @@ function maybeRequireExploration() {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('../../extra/exploration')
} else {
- return { FunnelExploration: null }
+ return { default: null }
}
}
-const Funnel = maybeRequire().default
-const { FunnelExploration } = maybeRequireExploration()
+const Funnel = maybeRequireFunnels().default
+const FunnelExploration = maybeRequireExploration().default
function singleGoalFilterApplied(dashboardState) {
const goalFilter = getGoalFilter(dashboardState)
@@ -304,7 +309,29 @@ function Behaviours({ importedDataInView, setMode, mode }) {
if (FunnelExploration === null) {
return featureUnavailable()
}
- return
+
+ if (site.explorationAvailable) {
+ return
+ }
+
+ const callToAction = { action: 'Upgrade', link: '/billing/choose-plan' }
+
+ return (
+
}
+ />
+ )
}
function renderFunnels() {
@@ -327,12 +354,15 @@ function Behaviours({ importedDataInView, setMode, mode }) {
return (
disableMode(Mode.FUNNELS)}
+ previewMock={
+ !site.funnelsAvailable ? : undefined
+ }
/>
)
} else {
@@ -360,12 +390,15 @@ function Behaviours({ importedDataInView, setMode, mode }) {
return (
disableMode(Mode.PROPS)}
+ previewMock={
+ !site.propsAvailable ? : undefined
+ }
/>
)
} else {
@@ -383,8 +416,14 @@ function Behaviours({ importedDataInView, setMode, mode }) {
function featureUnavailable() {
return (
-
- This feature is unavailable
+
)
}
@@ -537,7 +576,7 @@ function Behaviours({ importedDataInView, setMode, mode }) {
Funnels
))}
- {!site.isConsolidatedView && site.explorationAvailable && (
+ {!site.isConsolidatedView && isEnabled(Mode.EXPLORATION) && (
- "Funnels is part of the Plausible Business plan. To get access to this feature, please upgrade your account."
+ "Funnels and user journeys is part of the Plausible Business plan. To get access to this feature, please upgrade your account."
} == resp
end
end
diff --git a/test/plausible_web/controllers/stats_controller_test.exs b/test/plausible_web/controllers/stats_controller_test.exs
index 7d49250c951b..21758345d296 100644
--- a/test/plausible_web/controllers/stats_controller_test.exs
+++ b/test/plausible_web/controllers/stats_controller_test.exs
@@ -22,7 +22,7 @@ defmodule PlausibleWeb.StatsControllerTest do
assert text_of_attr(resp, @react_container, "data-props-available") == "true"
assert text_of_attr(resp, @react_container, "data-site-segments-available") == "true"
assert text_of_attr(resp, @react_container, "data-funnels-available") == "true"
- assert text_of_attr(resp, @react_container, "data-exploration-available") == "false"
+ assert text_of_attr(resp, @react_container, "data-exploration-available") == "true"
assert text_of_attr(resp, @react_container, "data-has-props") == "false"
assert text_of_attr(resp, @react_container, "data-logged-in") == "false"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "public"
@@ -150,17 +150,39 @@ defmodule PlausibleWeb.StatsControllerTest do
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
end
- test "non-superadmin can't see exploration funnel UI", %{conn: conn, site: site} do
- populate_stats(site, [build(:pageview)])
- conn = get(conn, "/" <> site.domain)
- resp = html_response(conn, 200)
- assert text_of_attr(resp, @react_container, "data-exploration-available") == "false"
- end
-
on_ee do
- test "superadmin can see exploration funnel UI", %{conn: conn, site: site, user: user} do
- patch_env(:super_admin_user_ids, [user.id])
+ test "can't see exploration funnel UI if funnels feature unavailable", %{
+ conn: conn,
+ site: site,
+ user: user
+ } do
+ subscribe_to_growth_plan(user)
populate_stats(site, [build(:pageview)])
+ conn = get(conn, "/" <> site.domain)
+ resp = html_response(conn, 200)
+ assert text_of_attr(resp, @react_container, "data-exploration-available") == "false"
+ end
+
+ test "can see exploration funnel UI on trial", %{conn: conn, site: site} do
+ populate_stats(site, [build(:pageview)])
+ conn = get(conn, "/" <> site.domain)
+ resp = html_response(conn, 200)
+ assert text_of_attr(resp, @react_container, "data-exploration-available") == "true"
+ end
+
+ test "can see exploration funnel UI past trial with funnels feature enabled", %{
+ conn: conn,
+ site: site,
+ user: user
+ } do
+ populate_stats(site, [build(:pageview)])
+
+ site.team
+ |> Plausible.Teams.Team.end_trial()
+ |> Plausible.Repo.update!()
+
+ subscribe_to_enterprise_plan(user, features: [Plausible.Billing.Feature.Funnels])
+
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-exploration-available") == "true"