render polls

This commit is contained in:
byte[] 2019-11-18 13:09:59 -05:00
parent 56fb4a154f
commit d0f53463a2
8 changed files with 94 additions and 5 deletions

View file

@ -4,14 +4,16 @@ defmodule Philomena.Polls.Poll do
alias Philomena.Topics.Topic alias Philomena.Topics.Topic
alias Philomena.Users.User alias Philomena.Users.User
alias Philomena.PollOptions.PollOption
schema "polls" do schema "polls" do
belongs_to :topic, Topic belongs_to :topic, Topic
belongs_to :deleted_by, User belongs_to :deleted_by, User
has_many :options, PollOption
field :title, :string field :title, :string
field :vote_method, :string field :vote_method, :string
field :active_until, :naive_datetime field :active_until, :utc_datetime
field :total_votes, :integer, default: 0 field :total_votes, :integer, default: 0
field :hidden_from_users, :boolean, default: false field :hidden_from_users, :boolean, default: false
field :deletion_reason, :string, default: "" field :deletion_reason, :string, default: ""

View file

@ -61,7 +61,7 @@ defmodule Philomena.Posts do
|> repo.one() |> repo.one()
Ecto.build_assoc(topic, :posts, [topic_position: (last_position || -1) + 1] ++ attributes) Ecto.build_assoc(topic, :posts, [topic_position: (last_position || -1) + 1] ++ attributes)
|> Post.creation_changeset(user, params) |> Post.creation_changeset(params, user)
|> repo.insert() |> repo.insert()
end) end)
|> Multi.run(:update_topic, fn repo, %{post: %{id: post_id}} -> |> Multi.run(:update_topic, fn repo, %{post: %{id: post_id}} ->

View file

@ -40,7 +40,7 @@ defmodule Philomena.Posts.Post do
end end
@doc false @doc false
def creation_changeset(post, user, attrs) do def creation_changeset(post, attrs, user) do
post post
|> cast(attrs, [:body, :anonymous]) |> cast(attrs, [:body, :anonymous])
|> set_name_at_post_time(user) |> set_name_at_post_time(user)

View file

@ -12,7 +12,7 @@ defmodule PhilomenaWeb.TopicController do
topic = topic =
Topic Topic
|> where(forum_id: ^forum.id, slug: ^slug, hidden_from_users: false) |> where(forum_id: ^forum.id, slug: ^slug, hidden_from_users: false)
|> preload(:user) |> preload([:user, poll: :option])
|> Repo.one() |> Repo.one()
conn = conn |> assign(:topic, topic) conn = conn |> assign(:topic, topic)

View file

@ -0,0 +1,13 @@
= if @poll.hidden_from_users do
.walloftext
.block.block--fixed.block--warning
h1 This poll has been deleted
p
' Reason:
strong
= @poll.deletion_reason || "Unknown (likely deleted in error). Please contact a moderator."
- else
.poll
.poll-area
= render PhilomenaWeb.TopicView, "_poll_results.html", poll: @poll, conn: @conn

View file

@ -0,0 +1,44 @@
.poll-results
h4.poll__header
' Poll results:
= @poll.title
.poll-option-list
elixir:
winning = winning_option(@poll)
winners? = @poll.total_votes > 0
= for option <- ranked_options(@poll) do
div class=option_class(option, winning, winners?)
.poll-option__text
span.poll-option__label = option.label
.poll-option__counts
span
=> percent_of_total(option, @poll)
=> option.vote_count
=> pluralize("vote", "votes", option.vote_count)
.poll-bar
svg.poll-bar__image width=percent_of_total(option, @poll) height="100%" viewBox="0 0 1 1" preserveAspectRatio="none"
rect class=poll_bar_class(option, winning, winners?) width="1" height="1"
= if active?(@poll) do
' Poll ends
= pretty_time(@poll.active_until)
' .
= if @poll.total_votes > 0 do
=> @poll.total_votes
=> pluralize("vote", "votes", @poll.total_votes)
- else
' No votes have been
' cast so far.
- else
' Poll ended
=> pretty_time(@poll.active_until)
' with
=> @poll.total_votes
= pluralize("vote", "votes", @poll.total_votes)
' .

View file

@ -29,7 +29,8 @@ h1 = @topic.title
= render PhilomenaWeb.Topic.SubscriptionView, "_subscription.html", forum: @forum, topic: @topic, watching: @watching, conn: @conn = render PhilomenaWeb.Topic.SubscriptionView, "_subscription.html", forum: @forum, topic: @topic, watching: @watching, conn: @conn
/ Display the poll, if any / Display the poll, if any
/= render partial: 'polls/display', locals: { poll: @topic.poll } = if @topic.poll do
= render PhilomenaWeb.Topic.PollView, "_display.html.slime", poll: @poll, conn: @conn
/ The actual posts / The actual posts
.posts-area .posts-area

View file

@ -0,0 +1,29 @@
defmodule PhilomenaWeb.Topic.PollView do
use PhilomenaWeb, :view
def ranked_options(poll) do
poll.options
|> Enum.sort_by(&{-&1.vote_count, &1.id})
end
def winning_option(poll) do
poll
|> ranked_options()
|> hd()
end
def active?(poll) do
not poll.hidden_from_users and poll.active_until > DateTime.utc_now()
end
def percent_of_total(_option, %{total_votes: 0}), do: 0
def percent_of_total(%{vote_count: vote_count}, %{total_votes: total_votes}) do
:io_lib.format("~.2f%", [(vote_count / total_votes * 100)])
end
def option_class(%{id: option_id}, %{id: option_id}, true), do: "poll-option-top"
def option_class(_option, _top_option, _winners?), do: nil
def poll_bar_class(%{id: option_id}, %{id: option_id}, true), do: "poll-bar__fill poll-bar__fill--top"
def poll_bar_class(_option, _top_option, _winners?), do: "poll-bar__fill"
end