Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 38 additions & 32 deletions lib/plausible_web/components/first_dashboard_launch_banner.ex
Original file line number Diff line number Diff line change
@@ -1,52 +1,58 @@
defmodule PlausibleWeb.Components.FirstDashboardLaunchBanner do
@moduledoc """
A banner that appears on the first dashboard launch
Dashboard banner pointing at email reports, shown once a site has stats and
only to roles that can access the email reports settings. Stays hidden while
the verification banner is up and reveals itself when that banner is dismissed.
"""

use PlausibleWeb, :component

attr(:site, Plausible.Site, required: true)

def set(assigns) do
~H"""
<script>
sessionStorage.setItem('<%= storage_key(@site) %>', false);
</script>
"""
end
@roles_with_email_reports_access [:owner, :admin, :editor, :super_admin]

attr(:site, Plausible.Site, required: true)
attr(:site_role, :atom, required: true)
attr(:current_user_id, :any, required: true)
attr(:has_pageviews?, :boolean, required: true)
attr(:verify_installation?, :boolean, default: false)

def render(assigns) do
assigns =
assign(
assigns,
:visible?,
assigns.has_pageviews? and assigns.site_role in @roles_with_email_reports_access
)

~H"""
<div
:if={@visible?}
x-cloak
x-data={x_data(@site)}
class="w-full px-4 text-sm font-bold text-center text-blue-900 bg-blue-200 rounded-sm transition"
style="top: 91px"
role="alert"
x-data={"{show: #{not @verify_installation?}}"}
x-bind:class="! show ? 'hidden' : ''"
x-init={x_init(@site)}
x-on:verification-finished.window="show = true"
role="alert"
>
<.styled_link
class="plausible-event-name=Weekly+Email+Note+Click"
href={Routes.site_path(PlausibleWeb.Endpoint, :settings_email_reports, @site.domain)}
<.notice
theme={:indigo}
dismissable_id={"first_dashboard_launched_#{@current_user_id}_#{@site.domain}"}
class="!p-4 text-center font-medium"
dismiss_class="top-1/2 -translate-y-1/2 right-4"
>
Get weekly traffic summaries by email →
</.styled_link>
<span class="text-base mr-1">
🎉
</span>
<span class="text-gray-900 dark:text-gray-100">
Your first pageview has landed!
</span>
<.styled_link
class="plausible-event-name=Weekly+Email+Note+Click"
href={Routes.site_path(PlausibleWeb.Endpoint, :settings_email_reports, @site.domain)}
onclick={"localStorage['notice_dismissed__first_dashboard_launched_#{@current_user_id}_#{@site.domain}'] = 'true'"}
>
Get weekly traffic reports by email →
</.styled_link>
</.notice>
</div>
"""
end

defp x_data(site) do
"{show: !!sessionStorage.getItem('#{storage_key(site)}')}"
end

defp x_init(site) do
"setTimeout(() => sessionStorage.removeItem('#{storage_key(site)}'), 3000)"
end

defp storage_key(site) do
"dashboard_seen_#{site.domain}"
end
end
8 changes: 7 additions & 1 deletion lib/plausible_web/components/generic.ex
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ defmodule PlausibleWeb.Components.Generic do
attr(:class, :string, default: "")
attr(:icon_class, :string, default: "")
attr(:title_class, :string, default: "")
attr(:dismiss_class, :string, default: "")
attr(:rest, :global)
slot(:inner_block)
slot(:actions)
Expand All @@ -248,7 +249,12 @@ defmodule PlausibleWeb.Components.Generic do
<div class={["rounded-md p-5 relative", @theme.bg, @class]} {@rest}>
<button
:if={@dismissable_id}
class={"absolute right-0 top-0 m-2 #{@theme.title_text}"}
class={[
"absolute",
@dismiss_class == "" && "right-0 top-0 m-2",
@theme.title_text,
@dismiss_class
]}
onclick={"localStorage['notice_dismissed__#{@dismissable_id}'] = 'true'; document.getElementById('#{@dismissable_id}').classList.add('hidden')"}
>
<Heroicons.x_mark class="h-4 w-4 hover:stroke-2" />
Expand Down
6 changes: 1 addition & 5 deletions lib/plausible_web/controllers/site_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,7 @@ defmodule PlausibleWeb.SiteController do
end

redirect(conn,
to:
Routes.site_path(conn, :installation, site.domain,
site_created: true,
flow: flow
)
to: Routes.site_path(conn, :installation, site.domain, flow: flow)
)

{:error, _, :permission_denied, _} ->
Expand Down
2 changes: 2 additions & 0 deletions lib/plausible_web/controllers/stats_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ defmodule PlausibleWeb.StatsController do
funnels: list_funnels(site),
has_props: Plausible.Props.configured?(site),
stats_start_date: stats_start_date,
has_pageviews?: !!stats_start_date,
native_stats_start_date: NaiveDateTime.to_date(site.native_stats_start_at),
title: title(conn, site),
demo: demo,
Expand Down Expand Up @@ -429,6 +430,7 @@ defmodule PlausibleWeb.StatsController do
exploration_max_journey_steps: exploration_max_journey_steps,
team_identifier: team_identifier,
limited_to_segment_id: limited_to_segment_id,
has_pageviews?: false,
verify_installation?: false,
verification_session: %{}
)
Expand Down
2 changes: 0 additions & 2 deletions lib/plausible_web/live/installation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ defmodule PlausibleWeb.Live.Installation do
{:ok,
assign(socket,
site: site,
site_created?: params["site_created"] == "true",
flow: flow
)}
end
Expand All @@ -104,7 +103,6 @@ defmodule PlausibleWeb.Live.Installation do
def render(assigns) do
~H"""
<div>
<PlausibleWeb.Components.FirstDashboardLaunchBanner.set :if={@site_created?} site={@site} />
<PlausibleWeb.Components.FlowProgress.render flow={@flow} current_step="Install Plausible" />

<.focus_box>
Expand Down
8 changes: 7 additions & 1 deletion lib/plausible_web/templates/stats/stats.html.heex
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<div class={stats_container_class(@conn)} data-site-domain={@site.domain}>
<PlausibleWeb.Components.FirstDashboardLaunchBanner.render site={@site} />
<PlausibleWeb.Components.FirstDashboardLaunchBanner.render
site={@site}
site_role={@site_role}
current_user_id={if user = @conn.assigns[:current_user], do: user.id}
has_pageviews?={@has_pageviews?}
verify_installation?={@verify_installation?}
/>

<%= if Plausible.Teams.locked?(@site.team) do %>
<div
Expand Down
12 changes: 6 additions & 6 deletions test/plausible_web/controllers/site_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ defmodule PlausibleWeb.SiteControllerTest do
})

assert redirected_to(conn) ==
"/#{URI.encode_www_form("éxample.com")}/installation?site_created=true&flow="
"/#{URI.encode_www_form("éxample.com")}/installation?flow="

assert site = Repo.get_by(Plausible.Site, domain: "éxample.com")
assert site.timezone == "Europe/London"
Expand Down Expand Up @@ -480,7 +480,7 @@ defmodule PlausibleWeb.SiteControllerTest do
}
})

assert redirected_to(conn) == "/example.com/installation?site_created=true&flow="
assert redirected_to(conn) == "/example.com/installation?flow="
assert Repo.get_by(Plausible.Site, domain: "example.com")
end

Expand All @@ -501,7 +501,7 @@ defmodule PlausibleWeb.SiteControllerTest do
}
})

assert redirected_to(conn) == "/example.com/installation?site_created=true&flow="
assert redirected_to(conn) == "/example.com/installation?flow="
assert Plausible.Teams.Billing.site_usage(team) == 3
end

Expand All @@ -515,7 +515,7 @@ defmodule PlausibleWeb.SiteControllerTest do
}
})

assert redirected_to(conn) == "/example.com/installation?site_created=true&flow="
assert redirected_to(conn) == "/example.com/installation?flow="
assert Repo.get_by(Plausible.Site, domain: "example.com")
end
end
Expand Down Expand Up @@ -555,7 +555,7 @@ defmodule PlausibleWeb.SiteControllerTest do
})

assert redirected_to(conn) ==
"/example.com%2Fsome_blog_site/installation?site_created=true&flow="
"/example.com%2Fsome_blog_site/installation?flow="
end

test "renders form again when it is a duplicate domain", %{conn: conn} do
Expand Down Expand Up @@ -618,7 +618,7 @@ defmodule PlausibleWeb.SiteControllerTest do
})

assert redirected_to(conn) ==
"/example.com/installation?site_created=true&flow="
"/example.com/installation?flow="
end

for role <- [:owner, :admin, :editor] do
Expand Down
70 changes: 70 additions & 0 deletions test/plausible_web/controllers/stats_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,66 @@ defmodule PlausibleWeb.StatsControllerTest do
end
end

describe "GET /:domain - first dashboard launch banner" do
setup [:create_user, :log_in, :create_site]

test "does not render when the site has no pageviews", %{conn: conn, site: site} do
resp = conn |> get("/" <> site.domain) |> html_response(200)
refute resp =~ "Your first pageview has landed!"
end

test "renders and is initially visible for the owner when the site has pageviews",
%{conn: conn, site: site, user: user} do
populate_stats(site, [build(:pageview)])
resp = conn |> get("/" <> site.domain) |> html_response(200)
assert resp =~ "Your first pageview has landed!"
assert resp =~ "{show: true}"

assert resp =~ "first_dashboard_launched_#{user.id}_#{site.domain}"
end

test "renders for editors and admins", %{conn: conn, user: user} do
for role <- [:editor, :admin] do
owner = new_user()
site = new_site(owner: owner)
add_member(site.team, user: user, role: role)
populate_stats(site, [build(:pageview)])

resp = conn |> get("/" <> site.domain) |> html_response(200)

assert resp =~ "Your first pageview has landed!",
"expected banner to render for role #{role}"
end
end

test "does not render for viewers even when the site has pageviews",
%{conn: conn, user: user} do
owner = new_user()
site = new_site(owner: owner)
add_member(site.team, user: user, role: :viewer)
populate_stats(site, [build(:pageview)])

resp = conn |> get("/" <> site.domain) |> html_response(200)
refute resp =~ "Your first pageview has landed!"
end

on_ee do
test "is rendered hidden while the verification banner is showing",
%{conn: conn, site: site} do
populate_stats(site, [build(:pageview)])

resp =
conn
|> get("/" <> site.domain <> "?verify_installation=true")
|> html_response(200)

assert resp =~ "Verifying your installation"
assert resp =~ "Your first pageview has landed!"
assert resp =~ "{show: false}"
end
end
end

describe "GET /:domain - as a super admin" do
@describetag :ee_only
setup [:create_user, :make_user_super_admin, :log_in]
Expand Down Expand Up @@ -645,6 +705,16 @@ defmodule PlausibleWeb.StatsControllerTest do
Plausible.Segments.to_response_map(%{emea_site_segment | owner_id: nil}, site)
])
end

test "does not render the first dashboard launch banner even with pageviews",
%{conn: conn} do
site = new_site(domain: "test-site.com")
populate_stats(site, [build(:pageview)])
link = insert(:shared_link, site: site)

resp = conn |> get("/share/test-site.com/?auth=#{link.slug}") |> html_response(200)
refute resp =~ "Your first pageview has landed!"
end
end

describe "GET /share/:slug - backwards compatibility" do
Expand Down
Loading