defmodule TarakanWeb.LeaderboardLive do use TarakanWeb, :live_view alias Tarakan.Leaderboard alias Tarakan.Profiles @sorts %{ "reputation" => :reputation, "reviews" => :reviews, "findings" => :findings, "verdicts" => :verdicts } @severities ~w(critical high medium low info) @windows %{"7" => 7, "30" => 30, "90" => 90, "all" => :all} @impl true def mount(_params, _session, socket) do {:ok, socket |> assign(:page_title, "Leaderboard") |> assign( :meta_description, "Who's putting work on the public record: reports, findings, checks." ) |> assign(:canonical_path, ~p"/leaderboard")} end @impl true def handle_params(params, _uri, socket) do sort = if is_map_key(@sorts, params["sort"]), do: params["sort"], else: "reputation" severity = if params["severity"] in @severities, do: params["severity"], else: nil window = if is_map_key(@windows, params["window"]), do: params["window"], else: "all" {:noreply, socket |> assign(:sort, sort) |> assign(:severity, severity) |> assign(:window, window) |> load_entries()} end @impl true def handle_event("sort", %{"by" => by}, socket) when is_map_key(@sorts, by) do {:noreply, patch_filters(socket, %{sort: by})} end def handle_event("filter_severity", %{"severity" => severity}, socket) do severity = if severity in @severities, do: severity, else: nil {:noreply, patch_filters(socket, %{severity: severity})} end def handle_event("filter_window", %{"window" => window}, socket) when is_map_key(@windows, window) do {:noreply, patch_filters(socket, %{window: window})} end defp patch_filters(socket, updates) do params = %{ sort: socket.assigns.sort, severity: socket.assigns.severity, window: socket.assigns.window } |> Map.merge(updates) # Keep the URL clean: defaults are implicit. |> Map.reject(fn {key, value} -> value in [nil, ""] or {key, value} in [sort: "reputation", window: "all"] end) push_patch(socket, to: ~p"/leaderboard?#{params}") end defp load_entries(socket) do opts = [ severity: socket.assigns.severity, window: Map.fetch!(@windows, socket.assigns.window) ] entries = Leaderboard.top(Map.fetch!(@sorts, socket.assigns.sort), opts) socket |> assign(:entries, entries) |> assign(:badges, Profiles.badges_for(Enum.map(entries, & &1.account.id))) end @doc false def tier_label("reviewer"), do: "Reviewer" def tier_label("contributor"), do: "Contributor" def tier_label(_new), do: "New" @doc false def badge_label(:first_blood), do: "First blood" def badge_label(:century), do: "Century" def badge_label(:eradicator), do: "Eradicator" def badge_label(:exorcist), do: "Exorcist" def badge_label(:sharpshooter), do: "Sharpshooter" def badge_label(badge), do: badge |> to_string() |> String.replace("_", " ") @doc false def rank_style(1), do: "text-signal" def rank_style(2), do: "text-ink" def rank_style(3), do: "text-ink-muted" def rank_style(_), do: "text-ink-faint" end