Packages

phoenix_kit

2.22.19
2.62.2 2.62.1 2.62.0 2.61.0 2.60.3 2.60.2 2.60.1 2.60.0 2.59.0 2.58.0 2.57.1 2.57.0 2.56.1 2.56.0 2.55.1 2.55.0 2.54.2 2.54.1 2.54.0 2.53.0 2.52.2 2.52.1 2.52.0 2.51.0 2.50.0 2.49.1 2.49.0 2.48.0 2.47.0 2.46.0 2.45.0 2.44.0 2.43.1 2.43.0 2.42.1 2.42.0 2.41.6 2.41.4 2.41.3 2.41.2 2.41.1 2.41.0 2.40.1 2.40.0 2.39.0 2.38.1 2.38.0 2.37.5 2.37.4 2.37.3 2.37.2 2.37.1 2.37.0 2.36.1 2.36.0 2.35.0 2.34.0 2.33.0 2.32.1 2.32.0 2.31.1 2.31.0 2.30.0 2.29.1 2.29.0 2.28.2 2.28.1 2.28.0 2.27.2 2.27.1 2.27.0 2.26.1 2.26.0 2.25.0 2.24.0 2.23.3 2.23.2 2.23.1 2.23.0 2.22.24 2.22.23 2.22.22 2.22.21 2.22.20 2.22.19 2.22.18 2.22.17 2.22.16 2.22.15 2.22.14 2.22.13 2.22.12 2.22.11 2.22.10 2.22.9 2.22.8 2.22.7 2.22.6 2.22.5 2.22.4 2.22.3 2.22.2 2.22.1 2.22.0 2.21.5 2.21.4 2.21.3 2.21.2 2.21.1 2.21.0 2.20.0 2.19.0 2.18.1 2.18.0 2.17.0 2.16.0 2.15.1 2.15.0 2.14.2 2.14.1 2.14.0 2.13.19 2.13.18 2.13.17 2.13.16 2.13.15 2.13.13 2.13.12 2.13.11 2.13.10 2.13.9 2.13.8 2.13.7 2.13.6 2.13.5 2.13.4 2.13.3 2.13.2 2.13.1 2.13.0 2.12.1 2.12.0 2.11.0 2.10.0 2.9.0 2.8.1 2.8.0 2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.0 2.0.1 2.0.0 1.7.236 1.7.235 1.7.234 1.7.233 1.7.232 1.7.231 1.7.230 1.7.229 1.7.228 1.7.227 1.7.226 1.7.225 1.7.224 1.7.223 1.7.222 1.7.221 1.7.220 1.7.219 1.7.218 1.7.217 1.7.216 1.7.215 1.7.214 1.7.213 1.7.212 1.7.211 1.7.210 1.7.209 1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit_web dashboard tabs_initializer.ex
Raw

lib/phoenix_kit_web/dashboard/tabs_initializer.ex

defmodule PhoenixKitWeb.Dashboard.TabsInitializer do
  @moduledoc """
  LiveView on_mount hook for initializing dashboard tabs with context-aware badge values.

  This hook should run AFTER `ContextProvider` to ensure context data is available.
  It automatically initializes dashboard tabs and loads badge values for context-aware
  badges, eliminating the need for custom on_mount hooks in most applications.

  ## Usage

  Add to your live_session after authentication and context hooks:

      live_session :dashboard,
        on_mount: [
          {PhoenixKitWeb.Users.Auth, :phoenix_kit_ensure_authenticated_scope},
          {PhoenixKitWeb.Dashboard.ContextProvider, :default},
          {PhoenixKitWeb.Dashboard.TabsInitializer, :default}
        ] do
        live "/dashboard", DashboardLive.Index
      end

  ## Mount Options

  - `:default` - Initialize tabs with presence tracking and badge subscriptions
  - `:minimal` - Initialize tabs without presence tracking (lower overhead)
  - `:badges_only` - Only initialize badge values, no presence tracking

  ## Assigns Set

  This hook sets the following assigns:

  - `@dashboard_tabs` - List of Tab structs with badge values loaded
  - `@tab_viewer_counts` - Map of tab_id => viewer count (unless `:minimal` or `:badges_only`)
  - `@collapsed_dashboard_groups` - MapSet of collapsed group IDs
  - `@context_badge_values` - Map of tab_id => badge value for context-aware badges

  ## How It Works

  1. Normalizes `current_contexts_map` for legacy single-selector configurations
     (builds `%{:default => current_context}` if `current_contexts_map` is not set)
  2. Calls `LiveTabs.init_dashboard_tabs/2` which:
     - Loads tabs from the Registry
     - Subscribes to tab update PubSub topics
     - Subscribes to badge update topics (with context placeholder resolution)
     - Loads initial values for context-aware badges via their loaders
     - Merges context values into tab badges

  ## Legacy Single-Selector Compatibility

  For apps using the legacy `:dashboard_context_selector` configuration,
  this hook automatically builds `current_contexts_map` from `current_context`:

      # Legacy config sets these:
      @current_context = %{id: 1, name: "My Farm"}
      @context_selector_config = %{key: :farm, ...}

      # This hook normalizes to:
      @current_contexts_map = %{farm: %{id: 1, name: "My Farm"}}

  This allows context-aware badges with `context_key: :farm` to work correctly.

  ## Manual Alternative

  If you need custom initialization logic, skip this hook and use
  `PhoenixKitWeb.Components.Dashboard.LiveTabs.init_dashboard_tabs/2` in your mount:

      def mount(_params, _session, socket) do
        socket = init_dashboard_tabs(socket)
        {:ok, socket}
      end

  ## Example with Context-Aware Badges

      # config.exs
      config :phoenix_kit, :user_dashboard_tabs, [
        %{
          id: :alerts,
          label: "Alerts",
          path: "alerts",
          badge: %{
            type: :count,
            context_key: :farm,  # Must match selector key
            loader: {MyApp.Alerts, :count_for_farm},
            color: :error
          }
        }
      ]

      # router.ex
      live_session :dashboard,
        on_mount: [
          {PhoenixKitWeb.Users.Auth, :phoenix_kit_ensure_authenticated_scope},
          {PhoenixKitWeb.Dashboard.ContextProvider, :default},
          {PhoenixKitWeb.Dashboard.TabsInitializer, :default}
        ] do
        live "/dashboard", DashboardLive.Index
      end

      # The badge will automatically show the correct count for the selected farm
  """

  import Phoenix.Component, only: [assign: 3]

  alias PhoenixKitWeb.Components.Dashboard.LiveTabs

  @doc """
  On mount hook that initializes dashboard tabs with badge values.

  ## Options

  - `:default` - Full initialization with presence tracking
  - `:minimal` - Skip presence tracking for lower overhead
  - `:badges_only` - Only initialize badge values
  """
  def on_mount(:default, _params, _session, socket) do
    socket =
      socket
      |> ensure_contexts_map()
      |> LiveTabs.init_dashboard_tabs(show_presence: true, subscribe_badges: true)

    {:cont, socket}
  end

  def on_mount(:minimal, _params, _session, socket) do
    socket =
      socket
      |> ensure_contexts_map()
      |> LiveTabs.init_dashboard_tabs(show_presence: false, subscribe_badges: true)

    {:cont, socket}
  end

  def on_mount(:badges_only, _params, _session, socket) do
    socket =
      socket
      |> ensure_contexts_map()
      |> LiveTabs.init_dashboard_tabs(show_presence: false, subscribe_badges: true)

    {:cont, socket}
  end

  # Ensures current_contexts_map is set, even in legacy single-selector mode.
  # This is necessary because:
  # - Multi-selector mode: ContextProvider sets current_contexts_map directly
  # - Legacy single-selector mode: ContextProvider only sets current_context
  # - Context-aware badges look for context in current_contexts_map[context_key]
  defp ensure_contexts_map(socket) do
    case socket.assigns[:current_contexts_map] do
      map when is_map(map) and map_size(map) > 0 ->
        # Already has contexts_map, nothing to do
        socket

      _ ->
        # Build from legacy assigns
        current_context = socket.assigns[:current_context]
        config = socket.assigns[:context_selector_config]

        # Use config key if available, otherwise :default
        key =
          cond do
            is_map(config) and Map.has_key?(config, :key) and config.key != nil -> config.key
            is_struct(config) and Map.has_key?(config, :key) and config.key != nil -> config.key
            true -> :default
          end

        contexts_map =
          if current_context do
            %{key => current_context}
          else
            %{}
          end

        assign(socket, :current_contexts_map, contexts_map)
    end
  end
end