Skip to content

Commit

Permalink
Intelligent / overridable Content List CTAs (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
amaisano authored Jul 24, 2019
1 parent 2b7807d commit 0d2a7f1
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 11 deletions.
8 changes: 8 additions & 0 deletions apps/content/lib/cms/static.ex
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ defmodule Content.CMS.Static do
parse_json("cms/teasers_diversion.json")
end

def teaser_empty_response do
[]
end

# Repositories of multiple, full-object responses (maximum data)

def news_repo do
Expand Down Expand Up @@ -375,6 +379,10 @@ defmodule Content.CMS.Static do
{:ok, teaser_project_update_response()}
end

def view("/cms/teasers", %{promoted: 0}) do
{:ok, teaser_empty_response()}
end

def view("/cms/teasers", %{type: :diversion}) do
{:ok, teaser_diversion_response()}
end
Expand Down
25 changes: 20 additions & 5 deletions apps/content/lib/paragraph/content_list.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ defmodule Content.Paragraph.ContentList do
This paragraph provides a formula for retreiving a dynamic list of
content items from the CMS via the `/cms/teasers` API endpoint.
"""
import Content.Helpers, only: [field_value: 2, int_or_string_to_int: 1, content_type: 1]
import Content.Helpers,
only: [field_value: 2, int_or_string_to_int: 1, content_type: 1, parse_link: 2]

import Content.Paragraph, only: [parse_header: 1]

alias Content.{Paragraph.ColumnMultiHeader, Repo, Teaser}
Expand All @@ -13,16 +15,20 @@ defmodule Content.Paragraph.ContentList do
right_rail: false,
ingredients: %{},
recipe: [],
teasers: []
teasers: [],
cta: %{}

@type order :: :DESC | :ASC

@type text_or_nil :: String.t() | nil

@type t :: %__MODULE__{
header: ColumnMultiHeader.t() | nil,
right_rail: boolean(),
ingredients: map(),
recipe: Keyword.t(),
teasers: [Teaser.t()]
teasers: [Teaser.t()],
cta: map()
}

@spec from_api(map) :: t
Expand Down Expand Up @@ -51,13 +57,22 @@ defmodule Content.Paragraph.ContentList do
sort_order: data |> field_value("field_sorting_logic") |> order()
}

cta_link = parse_link(data, "field_cta_link")

cta = %{
behavior: field_value(data, "field_cta_behavior"),
text: field_value(data, "field_cta_text"),
url: cta_link && Map.get(cta_link, :url)
}

recipe = combine(ingredients)

%__MODULE__{
header: parse_header(data),
right_rail: field_value(data, "field_right_rail"),
ingredients: ingredients,
recipe: recipe
recipe: recipe,
cta: cta
}
end

Expand Down Expand Up @@ -207,7 +222,7 @@ defmodule Content.Paragraph.ContentList do
end

# Convert order value strings to atoms
@spec order(String.t() | nil) :: order()
@spec order(text_or_nil) :: order()
defp order("ASC"), do: :ASC
defp order("DESC"), do: :DESC
defp order(_), do: nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@
teasers: @content.teasers,
type: Keyword.get(@content.recipe, :type, :generic),
conn: @conn) %>

<%= if list_cta?(@content.ingredients.type, @content.cta, @content.teasers, @conn.path_info) do %>
<% cta = setup_list_cta(@content, @conn.path_info) %>

<p>
<%= link cta.title, to: cms_static_page_path(@conn, cta.url), class: "c-call-to-action" %>
</p>
<% end %>
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
%>

<%= link to: cms_static_page_path(@conn, teaser.path), id: teaser.id,
class: "c-content-teaser c-content-teaser--#{css_type} c-content-teaser--#{color}" do %>
class: "c-content-teaser c-content-teaser--#{css_type} c-content-teaser--#{color}" do %>
<%= SiteWeb.Content.TeaserView.render("_#{@type}.html", teaser: teaser, conn: @conn) %>
<% end %>

<% end %>
</div>
</div>
100 changes: 98 additions & 2 deletions apps/site/lib/site_web/views/content_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ defmodule SiteWeb.ContentView do

import SiteWeb.TimeHelpers

alias Content.CMS
alias Content.Field.{File, Image, Link}
alias Content.Paragraph
alias Content.Paragraph.{Callout, ColumnMulti, ContentList, FareCard}
alias Content.Teaser
alias Plug.Conn
alias Site.ContentRewriter

defdelegate fa_icon_for_file_type(mime), to: Site.FontAwesomeHelpers
Expand All @@ -25,7 +28,7 @@ defmodule SiteWeb.ContentView do
end

@doc "Universal wrapper around all paragraph types"
@spec render_paragraph(Paragraph.t(), Plug.Conn.t()) :: Phoenix.HTML.safe()
@spec render_paragraph(Paragraph.t(), Conn.t()) :: Phoenix.HTML.safe()
# Don't render Content List if list has no items
def render_paragraph(%ContentList{teasers: []}, _), do: []

Expand All @@ -43,7 +46,7 @@ defmodule SiteWeb.ContentView do
Intelligently choose and render paragraph template based on type, except
for certain types which either have no template or require special values.
"""
@spec render_content(Paragraph.t(), Plug.Conn.t()) :: Phoenix.HTML.safe()
@spec render_content(Paragraph.t(), Conn.t()) :: Phoenix.HTML.safe()
def render_content(paragraph, conn)

def render_content(%ColumnMulti{display_options: "grouped"} = paragraph, conn) do
Expand Down Expand Up @@ -132,6 +135,48 @@ defmodule SiteWeb.ContentView do
end
end

@spec list_cta?(CMS.type(), map(), [Teaser.t()], [String.t()]) :: boolean()
# No results
def list_cta?(_type, _cta, [], _path) do
false
end

# Is not requested (hide)
def list_cta?(_type, %{behavior: "hide"}, _teasers, _path) do
false
end

# Is a list of project updates, AND is sitting on a valid project page
def list_cta?(:project_update, _cta, _teasers, ["projects", _]) do
true
end

# Is requested (auto/overridden) BUT has no default (generic destination) AND user has not provided a link
def list_cta?(type, %{url: url, text: text}, _teasers, _path)
when type in [:project_update, :diversion, :page] and (is_nil(url) or is_nil(text)) do
false
end

# Either has required link values or has a readily available default link path
def list_cta?(_type, _cta, _teasers, _path) do
true
end

@spec setup_list_cta(ContentList.t(), [String.t()]) :: Link.t()
def setup_list_cta(list, conn_path) do
current_path =
["" | conn_path]
|> Enum.join("/")

case list.cta do
%{text: nil, url: nil} ->
default_list_cta(list.ingredients.type, current_path)

link_parts ->
custom_list_cta(list.ingredients.type, link_parts, current_path)
end
end

defp maybe_shift_timezone(%NaiveDateTime{} = time) do
time
end
Expand Down Expand Up @@ -191,4 +236,55 @@ defmodule SiteWeb.ContentView do
@spec paragraph_classes(Paragraph.t()) :: iodata()
defp paragraph_classes(%Callout{image: %Image{}}), do: ["c-callout--with-image"]
defp paragraph_classes(_), do: []

# Automatically map each list to a destination page based on content type
@spec default_list_cta(CMS.type(), String.t()) :: Link.t()
defp default_list_cta(:project_update, current_path) do
%Link{
title: "View all project updates",
url: "#{current_path}/updates"
}
end

defp default_list_cta(:event, _current_path) do
%Link{
title: "View all events",
url: "/events"
}
end

defp default_list_cta(:news_entry, _current_path) do
%Link{
title: "View all news",
url: "/news"
}
end

defp default_list_cta(:project, _current_path) do
%Link{
title: "View all projects",
url: "/projects"
}
end

# Override one or both of the url/text values for the list CTA
@spec custom_list_cta(CMS.type(), map, String.t()) :: Link.t()
defp custom_list_cta(type, %{text: nil, url: url}, current_path) do
type
|> default_list_cta(current_path)
|> Map.put(:url, url)
end

defp custom_list_cta(type, %{text: text, url: nil}, current_path) do
type
|> default_list_cta(current_path)
|> Map.put(:title, text)
end

defp custom_list_cta(_type, %{text: text, url: url}, _current_path) do
%Link{
title: text,
url: url
}
end
end
Loading

0 comments on commit 0d2a7f1

Please sign in to comment.