From 9eaff6731861f9125c38341c2e757cf799665698 Mon Sep 17 00:00:00 2001 From: Ben Halpern Date: Thu, 30 Nov 2023 16:07:16 -0500 Subject: [PATCH] Update styling and refine features for analytics page (#20410) * Update styling and refine features for analytics page * Remove follower reference from js * Update html * Adjust test --- app/assets/stylesheets/dashboard.scss | 19 +++++-- app/controllers/articles_controller.rb | 1 + app/controllers/dashboards_controller.rb | 1 + app/javascript/analytics/dashboard.js | 30 ++--------- app/models/reaction.rb | 8 +++ app/views/articles/stats.html.erb | 5 +- app/views/dashboards/_analytics.html.erb | 7 ++- app/views/dashboards/analytics.erb | 8 +-- app/views/shared/_stats.html.erb | 54 ++++++++++++------- config/locales/views/dashboard/en.yml | 7 ++- config/locales/views/dashboard/fr.yml | 4 +- config/locales/views/misc/en.yml | 7 +-- .../analyticsNavigation.spec.js | 2 +- .../dashboardFlows/postsDashboard.spec.js | 2 +- 14 files changed, 87 insertions(+), 68 deletions(-) diff --git a/app/assets/stylesheets/dashboard.scss b/app/assets/stylesheets/dashboard.scss index 13b777e12..3aa8f0828 100644 --- a/app/assets/stylesheets/dashboard.scss +++ b/app/assets/stylesheets/dashboard.scss @@ -259,13 +259,16 @@ } .analytics-container { - width: 1400px; + max-width: 1400px; margin: 0 auto; } .crayons-tabs--analytics { width: min-content; - margin: var(--su-8) auto; + margin: var(--su-1) auto var(--su-4); + @media screen and (min-width: 800px) { + margin: var(--su-1) var(--su-4) var(--su-4); + } } $column-flex: 1; @@ -277,6 +280,7 @@ $column-flex: 1; &__col { flex: $column-flex; + min-height: 100px; } } @@ -285,13 +289,19 @@ $column-flex: 1; } .graphs { - text-align: center; display: flex; justify-content: space-between; - &__col { flex: $column-flex; } + .charts-container { + padding: var(--su-4); + height: 320px; + canvas { + min-height: 280px; + max-height: 280px; + } + } } @media screen and (max-width: $breakpoint-s) { @@ -357,6 +367,7 @@ $column-flex: 1; .featured-stat { font-size: 2em; + font-weight: bold; } .header-card { diff --git a/app/controllers/articles_controller.rb b/app/controllers/articles_controller.rb index 50150aec1..28d04d100 100644 --- a/app/controllers/articles_controller.rb +++ b/app/controllers/articles_controller.rb @@ -207,6 +207,7 @@ class ArticlesController < ApplicationController def stats authorize @article @organization_id = @article.organization_id + @reactions = @article.reactions.public_category.order(created_at: :desc).limit(500).includes(:user) end def admin_unpublish diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb index 2cb2794ce..a392080df 100644 --- a/app/controllers/dashboards_controller.rb +++ b/app/controllers/dashboards_controller.rb @@ -42,6 +42,7 @@ class DashboardsController < ApplicationController end @reactions_count = @articles.sum(&:public_reactions_count) + @comments_count = @articles.sum(&:comments_count) @page_views_count = @articles.sum(&:page_views_count) @articles = @articles.includes(:collection).sorting(params[:sort]).decorate diff --git a/app/javascript/analytics/dashboard.js b/app/javascript/analytics/dashboard.js index d309dba83..ddf8557b1 100644 --- a/app/javascript/analytics/dashboard.js +++ b/app/javascript/analytics/dashboard.js @@ -31,17 +31,14 @@ function writeCards(data, timeRangeLabel) { const readers = sumAnalytics(data, 'page_views'); const reactions = sumAnalytics(data, 'reactions'); const comments = sumAnalytics(data, 'comments'); - const follows = sumAnalytics(data, 'follows'); const reactionCard = document.getElementById('reactions-card'); const commentCard = document.getElementById('comments-card'); - const followerCard = document.getElementById('followers-card'); const readerCard = document.getElementById('readers-card'); readerCard.innerHTML = cardHTML(readers, `Readers ${timeRangeLabel}`); commentCard.innerHTML = cardHTML(comments, `Comments ${timeRangeLabel}`); reactionCard.innerHTML = cardHTML(reactions, `Reactions ${timeRangeLabel}`); - followerCard.innerHTML = cardHTML(follows, `Followers ${timeRangeLabel}`); } function drawChart({ id, showPoints = true, title, labels, datasets }) { @@ -121,7 +118,6 @@ function drawCharts(data, timeRangeLabel) { const likes = parsedData.map((date) => date.reactions.like); const readingList = parsedData.map((date) => date.reactions.readinglist); const unicorns = parsedData.map((date) => date.reactions.unicorn); - const followers = parsedData.map((date) => date.follows.total); const readers = parsedData.map((date) => date.page_views.total); // When timeRange is "Infinity" we hide the points to avoid over-crowding the UI @@ -185,23 +181,6 @@ function drawCharts(data, timeRangeLabel) { ], }); - drawChart({ - id: 'followers-chart', - showPoints, - title: `New Followers ${timeRangeLabel}`, - labels, - datasets: [ - { - label: 'Followers', - data: followers, - fill: false, - borderColor: 'rgb(10, 133, 255)', - backgroundColor: 'rgb(10, 133, 255)', - lineTension: 0.1, - }, - ], - }); - drawChart({ id: 'readers-chart', showPoints, @@ -250,20 +229,21 @@ function renderReferrers(data) { } function removeCardElements() { - const el = document.getElementsByClassName("summary-stats")[0]; + const el = document.getElementsByClassName('summary-stats')[0]; el && el.remove(); } function showErrorsOnCharts() { - const target = ['reactions-chart', 'comments-chart', 'followers-chart', 'readers-chart']; - target.forEach(id => { + const target = ['reactions-chart', 'comments-chart', 'readers-chart']; + target.forEach((id) => { const el = document.getElementById(id); el.outerHTML = `

Failed to fetch chart data. If this error persists for a minute, you can try to disable adblock etc. on this page or site.

`; }); } function showErrorsOnReferrers() { - document.getElementById('referrers-container').outerHTML = '

Failed to fetch referrer data. If this error persists for a minute, you can try to disable adblock etc. on this page or site.

'; + document.getElementById('referrers-container').outerHTML = + '

Failed to fetch referrer data. If this error persists for a minute, you can try to disable adblock etc. on this page or site.

'; } function callAnalyticsAPI(date, timeRangeLabel, { organizationId, articleId }) { diff --git a/app/models/reaction.rb b/app/models/reaction.rb index be83b9b86..81e32b04d 100644 --- a/app/models/reaction.rb +++ b/app/models/reaction.rb @@ -176,6 +176,14 @@ class Reaction < ApplicationRecord ReactionCategory[category.to_sym] end + def readable_date + if created_at.year == Time.current.year + I18n.l(created_at, format: :short) + else + I18n.l(created_at, format: :short_with_yy) + end + end + private def update_reactable diff --git a/app/views/articles/stats.html.erb b/app/views/articles/stats.html.erb index 5757c6821..3f1ac1224 100644 --- a/app/views/articles/stats.html.erb +++ b/app/views/articles/stats.html.erb @@ -1,7 +1,8 @@ <% title t("views.stats.meta.title") %> -
-

<%= t("views.stats.heading_html", article: link_to(@article.title, @article.current_state_path, id: "article", data: { "article-id" => @article.id, "organization-id" => @organization_id })) %>

+
+

+ <%= link_to(@article.title, @article.current_state_path, id: "article", data: { "article-id" => @article.id, "organization-id" => @organization_id }) %>

<%= render "shared/stats" %>
diff --git a/app/views/dashboards/_analytics.html.erb b/app/views/dashboards/_analytics.html.erb index 5f9d95b5f..0f040de46 100644 --- a/app/views/dashboards/_analytics.html.erb +++ b/app/views/dashboards/_analytics.html.erb @@ -1,11 +1,16 @@ <% num_views = @page_views_count %> -
+
<%= number_with_delimiter(@reactions_count, delimiter: ",") %> <%= t("views.dashboard.summary.reactions") %>
+
+ <%= number_with_delimiter(@comments_count, delimiter: ",") %> + <%= t("views.dashboard.summary.comments") %> +
+
<%= num_views > 500 ? number_with_delimiter(num_views, delimiter: ",") : t("views.dashboard.summary.lt_500") %> <%= t("views.dashboard.summary.views") %> diff --git a/app/views/dashboards/analytics.erb b/app/views/dashboards/analytics.erb index d42145eda..c64b7239f 100644 --- a/app/views/dashboards/analytics.erb +++ b/app/views/dashboards/analytics.erb @@ -1,7 +1,7 @@ <% title t("views.dashboard.analytics.meta.title") %>
-
diff --git a/app/views/shared/_stats.html.erb b/app/views/shared/_stats.html.erb index 585721ce1..d8716b35c 100644 --- a/app/views/shared/_stats.html.erb +++ b/app/views/shared/_stats.html.erb @@ -22,43 +22,35 @@
-
-
-
-
+
-

<%= t("views.stats.readers") %>

+

<%= t("views.stats.readers") %>

-
-

<%= t("views.stats.followers") %>

-
- -
-
-
-
-

<%= t("views.stats.reactions") %>

+
+
+

<%= t("views.stats.reactions") %>

-
-

<%= t("views.stats.comments") %>

+
+

<%= t("views.stats.comments") %>

-
-

<%= t("views.stats.traffic.text") %>

+
+
+

<%= t("views.stats.traffic.text") %>

@@ -70,4 +62,30 @@
+
+ + <% if @reactions && @reactions.any? %> +
+

+ <%= t("views.stats.reactions_history") %> +

+ <% @reactions.each do |reaction| %> +
+
+ + +
+
+
+ <%= reaction.category %> + by <%= reaction.user.name %> +
+
+ <%= reaction.readable_date %> +
+
+
+ <% end %> +
+ <% end %>
diff --git a/config/locales/views/dashboard/en.yml b/config/locales/views/dashboard/en.yml index 62166ae5f..7d7563621 100644 --- a/config/locales/views/dashboard/en.yml +++ b/config/locales/views/dashboard/en.yml @@ -29,10 +29,8 @@ en: analytics: meta: title: Analytics - heading: Analytics Dashboard for %{name} - desc_1: Welcome to the Analytics Dashboard, the home of in-depth user metrics so that authors can make data-driven decisions about the %{members} ecosystem. - desc_2: This dashboard highlights deep insights especially relevant to %{members} relations, authors, and serious bloggers. - back: "👈 Back to Main Dashboard" + heading: Analytics for %{name} + back: "Back to Main Dashboard" your: Your Dashboard org: "%{org} Analytics Dashboard" article: @@ -154,6 +152,7 @@ en: summary: reactions: Total post reactions views: Total post views + comments: Total post comments listings: Listings created credits: Credits available lt_500: "< 500" diff --git a/config/locales/views/dashboard/fr.yml b/config/locales/views/dashboard/fr.yml index 597e49433..de5f96ab3 100644 --- a/config/locales/views/dashboard/fr.yml +++ b/config/locales/views/dashboard/fr.yml @@ -30,9 +30,7 @@ fr: meta: title: Analytics heading: Analytics Dashboard for %{name} - desc_1: Welcome to the Analytics Dashboard, the home of in-depth user metrics so that authors can make data-driven decisions about the %{members} ecosystem. - desc_2: This dashboard highlights deep insights especially relevant to %{members} relations, authors, and serious bloggers. - back: "👈 Back to Main Dashboard" + back: "Back to Main Dashboard" your: Your Dashboard org: "%{org} Analytics Dashboard" article: diff --git a/config/locales/views/misc/en.yml b/config/locales/views/misc/en.yml index 5920aafd6..78f4012ae 100644 --- a/config/locales/views/misc/en.yml +++ b/config/locales/views/misc/en.yml @@ -116,12 +116,13 @@ en: infinity: Infinity readers: Readers Summary followers: New Followers Summary - reactions: "Reactions Summary ❤🦄🔖" - comments: "Comments Summary 💬" + reactions: "Reactions Summary" + comments: "Comments Summary" traffic: - text: "Traffic Source Summary 🚦" + text: "Traffic Source Summary" source: Source views: Views + reactions_history: "Reactions History" sticky: joined: Joined default_cta: Learn more diff --git a/cypress/e2e/seededFlows/analyticsFlows/analyticsNavigation.spec.js b/cypress/e2e/seededFlows/analyticsFlows/analyticsNavigation.spec.js index 77c257734..231f88704 100644 --- a/cypress/e2e/seededFlows/analyticsFlows/analyticsNavigation.spec.js +++ b/cypress/e2e/seededFlows/analyticsFlows/analyticsNavigation.spec.js @@ -65,7 +65,7 @@ describe('Analytics navigation', () => { it('should navigate to correct organization analytics dashboard', () => { cy.findByText('Bachmanity Analytics Dashboard').click(); - cy.contains('h1', 'Analytics Dashboard for Bachmanity'); + cy.contains('h1', 'Analytics for Bachmanity'); }); }); }); diff --git a/cypress/e2e/seededFlows/dashboardFlows/postsDashboard.spec.js b/cypress/e2e/seededFlows/dashboardFlows/postsDashboard.spec.js index cc4d20617..7d94890cc 100644 --- a/cypress/e2e/seededFlows/dashboardFlows/postsDashboard.spec.js +++ b/cypress/e2e/seededFlows/dashboardFlows/postsDashboard.spec.js @@ -48,7 +48,7 @@ describe('Posts Dashboard', () => { name: 'More options for post: Test Article', }).click(); cy.findByRole('link', { name: 'Stats' }).click(); - cy.findByRole('heading', { name: 'Stats for "Test Article"' }); + cy.findByRole('heading', { name: 'Test Article' }); // Go back to the dashboard, otherwise it's possible for Cypress to detect an error as the next beforeEach hook runs // (due to the logged out user not being able to view the stats page)