List and show events (#17)

* Improve Directus client

- Rearrange and group functions to match
- Allow whitespace when searching
- provide category to event list

* Add event list view

* Show band information on festival-ish events

* Extract view helpers to reusable module

Code is shared between ItemHTML and PageHTML,
and they really do not belong in web anyway
since it is usable outside web scope as well.

* Rename utils to event helpers

It is a file that handles the poor design choice
of the datamodel for events, so let the module
name describe that.

* Sync event view

- Replace scaffold markup with production markup
- Send more data from Directus client
This commit is contained in:
Anders Englöf Ytterström 2024-10-03 22:52:40 +02:00 committed by GitHub
parent bb3726d071
commit a6d34d17fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 209 additions and 46 deletions

View file

@ -25,19 +25,19 @@ defmodule Mse25.Directus do
get("/articles?" <> params) get("/articles?" <> params)
end end
def get_event(slug) do def get_album(externalId) do
get_item( get_item(
:events, :albums,
slug, externalId,
[ [
"*", "purchased_at",
"location.*", "album",
"poster.filename_download", "year",
"poster.width", "youtubeId",
"poster.height", "externalId",
"bands.artists_id.name", "cover",
"mia.artists_id.name", "songs.title",
"location.name" "songs.artist.name"
] ]
|> Enum.join(",") |> Enum.join(",")
) )
@ -71,21 +71,16 @@ defmodule Mse25.Directus do
end) end)
end end
def get_album(externalId) do def get_event(slug) do
get_item( get_item(
:albums, :events,
externalId, slug,
[ [
"purchased_at", "*",
"album", "location.*",
"year", "poster",
"youtubeId", "bands.artists_id.name",
"externalId", "mia.artists_id.name"
"cover.filename_download",
"cover.width",
"cover.height",
"songs.title",
"songs.artist.name"
] ]
|> Enum.join(",") |> Enum.join(",")
) )
@ -108,9 +103,8 @@ defmodule Mse25.Directus do
"title", "title",
"lead", "lead",
"slug", "slug",
"poster.filename_download", "poster",
"poster.width", "category",
"poster.height",
"bands.artists_id.name", "bands.artists_id.name",
"mia.artists_id.name" "mia.artists_id.name"
], ],
@ -218,7 +212,7 @@ defmodule Mse25.Directus do
case opts[:query] do case opts[:query] do
nil -> params nil -> params
"" -> params "" -> params
pg -> ["filter[title][_icontains]=" <> to_string(pg) | params] pg -> ["filter[title][_icontains]=" <> String.replace(to_string(pg), " ", "%20") | params]
end end
end end
end end

View file

@ -0,0 +1,33 @@
defmodule Mse25.EventHelpers do
def bandlist(bands) do
bands
|> Enum.map(fn b -> b["artists_id"]["name"] end)
|> Enum.join(", ")
|> String.replace(~r/, ([^,]+?)$/, " och \\1")
end
def hilights?(%{"bands" => bands, "category" => category}) do
_festival_band?(bands, category)
end
def missed?(%{"mia" => bands, "category" => category}) do
_festival_band?(bands, category)
end
def opening_acts?(%{"bands" => [_ | bands], "category" => "concert"}) do
not Enum.empty?(bands)
end
def opening_acts?(_) do
false
end
def _festival_band?(bands, category)
when category in ["cruise", "openairfestival", "cityfestival", "onedayfestival"] do
not Enum.empty?(bands)
end
def _festival_band?(_b, _c) do
false
end
end

View file

@ -67,16 +67,23 @@ defmodule Mse25Web.ItemController do
defp assigns(:event, %{ defp assigns(:event, %{
"title" => heading, "title" => heading,
"contents" => contents, "contents" => contents,
"started_at" => published_at, "started_at" => started_at,
"lead" => lead "lead" => lead,
"poster" => poster,
"bands" => bands,
"mia" => mia,
"category" => category
}) do }) do
[ [
page_title: heading, page_title: heading,
heading: heading, heading: heading,
contents: Earmark.as_html!(contents), contents: Earmark.as_html!(contents),
published_at: published_at,
lead: lead, lead: lead,
year: String.slice(published_at, 0..3) year: String.slice(started_at, 0..3),
poster: poster,
bands: bands,
mia: mia,
category: category
] ]
end end

View file

@ -1,5 +1,6 @@
defmodule Mse25Web.ItemHTML do defmodule Mse25Web.ItemHTML do
use Mse25Web, :html use Mse25Web, :html
import Mse25.EventHelpers
embed_templates "item_html/*" embed_templates "item_html/*"
end end

View file

@ -1,9 +1,45 @@
<article> <article class="article">
<header> <header>
<date><%= @published_at %></date> <ol class="breadcrumbs" itemscope itemtype="https://schema.org/BreadcrumbList">
<h1><%= @heading %></h1> <li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
</header> <a href="/" rel="home">
<span itemprop="name">madr.se</span>
</a>
<meta itemprop="position" content="1" />
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a href="/evenemang">
<span itemprop="name">Evenemang</span>
</a>
<meta itemprop="position" content="2" />
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a href={"/" <> @year}>
<span itemprop="name"><%= @year %></span>
</a>
<meta itemprop="position" content="3" />
</li>
</ol>
<h1><%= @heading %></h1>
</header>
<%= raw @contents %> <ul>
<li><%= @lead %></li>
<%= if opening_acts?(%{"bands" => @bands, "category" => @category}) do %>
<li>Huvudakt: <%= @bands |> List.first() |> Map.get("artists_id") |> Map.get("name") %></li>
<li>Förband: <%= @bands |> Enum.drop(1) |> bandlist() %></li>
<% end %>
<%= if hilights?(%{"bands" => @bands, "category" => @category}) do %>
<li>Personliga höjdpunkter: <%= @bands |> bandlist() %></li>
<% end %>
<%= if missed?(%{"mia" => @mia, "category" => @category}) do %>
<li>Band jag missade: <%= @mia |> bandlist() %></li>
<% end %>
</ul>
<%= raw(@contents) %>
<%= if @poster do %>
<img src={"https://n.madr.se/assets/" <> @poster} alt="affisch" loading="lazy" />
<% end %>
</article> </article>

View file

@ -20,9 +20,9 @@ defmodule Mse25Web.PageController do
) )
end end
def articles(conn, _params) do def articles(conn, params) do
articles = articles =
case conn.params do case params do
%{"q" => query_string} -> Directus.get_articles!(limit: 9999, query: query_string) %{"q" => query_string} -> Directus.get_articles!(limit: 9999, query: query_string)
_ -> Directus.get_articles!(limit: 9999) _ -> Directus.get_articles!(limit: 9999)
end end
@ -31,8 +31,27 @@ defmodule Mse25Web.PageController do
render(conn, :articles, render(conn, :articles,
page_title: "Webblogg", page_title: "Webblogg",
articles: articles, articles: articles,
q: conn.params["q"], q: params["q"],
nosearch?: conn.params["q"] == nil or conn.params["q"] == "" nosearch?: params["q"] == nil or params["q"] == ""
)
end
def events(conn, params) do
{_, %{"title" => title, "contents" => contents}} = Directus.get_page("evenemang")
events =
case params do
%{"q" => query_string} -> Directus.get_events!(limit: 9999, query: query_string)
_ -> Directus.get_events!(limit: 9999)
end
|> group_annually
render(conn, :events,
page_title: title,
contents: Earmark.as_html!(contents),
events: events,
q: params["q"],
nosearch?: params["q"] == nil or params["q"] == ""
) )
end end

View file

@ -5,6 +5,7 @@ defmodule Mse25Web.PageHTML do
See the `page_html` directory for all templates available. See the `page_html` directory for all templates available.
""" """
use Mse25Web, :html use Mse25Web, :html
import Mse25.EventHelpers
embed_templates "page_html/*" embed_templates "page_html/*"
end end

View file

@ -0,0 +1,72 @@
<header>
<ol class="breadcrumbs" itemscope itemtype="https://schema.org/BreadcrumbList">
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a href="/" rel="home">
<span itemprop="name">madr.se</span>
</a>
<meta itemprop="position" content="1" />
</li>
</ol>
<h1><%= @page_title %></h1>
<%= raw(@contents) %>
<p>
<%= if @nosearch? do %>
Gå direkt till:
<% end %>
</p>
<ul class="months">
<%= for {year, events} <- @events do %>
<li>
<a href={"#y" <> year}><%= year %></a> (<%= Enum.count(events) %>)
</li>
<% end %>
</ul>
<form method="get" action="/evenemang">
<p>
<%= if @nosearch? do %>
Eller
<% end %>
<label for="q">sök innehåll</label>:
<input type="search" value={@q} name="q" id="q" size="7" />
<button>Sök</button>
</p>
</form>
<%= for {year, events} <- @events do %>
<section id={"y" <> year}>
<h2 class="sticky"><%= year %></h2>
<div class="events">
<%= for event <- events do %>
<article>
<h2>
<a href={"/" <> event["slug"]}><%= event["title"] %></a>
</h2>
<p><%= event["lead"] %></p>
<%= if hilights?(event) do %>
<p>
Personliga höjdpunkter: <%= bandlist(event["bands"]) %>
</p>
<% end %>
<%= if missed?(event) do %>
<p>
Band jag missade: <%= bandlist(event["mia"]) %>
</p>
<% end %>
<%= if opening_acts?(event) do %>
<p>
Förband: <%= event["bands"] |> Enum.drop(1) |> bandlist() %>
</p>
<% end %>
<%= if event["poster"] do %>
<img
loading="lazy"
src={"https://n.madr.se/assets/" <> event["poster"]}
alt="affisch"
width="150"
/>
<% end %>
</article>
<% end %>
</div>
</section>
<% end %>
</header>

View file

@ -19,15 +19,15 @@ defmodule Mse25Web.Router do
get "/", PageController, :home get "/", PageController, :home
# get "/evenemang", EventController, :index get "/evenemang", PageController, :events
# get "/kommande-evenemang.ics", EventController, :calendar
# get "/event-map.js", EventController, :interactive_map
get "/webblogg", PageController, :articles get "/webblogg", PageController, :articles
get "/delningar", PageController, :links get "/delningar", PageController, :links
# get "/kommande-evenemang.ics", EventController, :calendar
# get "/event-map.js", EventController, :interactive_map
# get "/:year", TimelineController, :annual # get "/:year", TimelineController, :annual
# get "/prenumerera.xml", TimelineController, :feed # get "/prenumerera.xml", TimelineController, :feed
get "/*path", ItemController, :index get "/*path", ItemController, :index
end end