show evolutions as well
All checks were successful
Build and Deploy / Build & Push Image (push) Successful in 33s
All checks were successful
Build and Deploy / Build & Push Image (push) Successful in 33s
This commit is contained in:
@@ -64,7 +64,8 @@ defmodule CobblemonUiWeb.DashboardLive do
|
||||
end
|
||||
|
||||
def handle_params(_params, _uri, socket) do
|
||||
{:noreply, assign(socket, selected_player: nil, player_data: nil, battle: nil, selected_pokemon: nil)}
|
||||
{:noreply,
|
||||
assign(socket, selected_player: nil, player_data: nil, battle: nil, selected_pokemon: nil)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -93,13 +94,11 @@ defmodule CobblemonUiWeb.DashboardLive do
|
||||
{:noreply, assign(socket, view_mode: String.to_existing_atom(mode), selected_pokemon: nil)}
|
||||
end
|
||||
|
||||
|
||||
@impl true
|
||||
def handle_info(:tick, socket) do
|
||||
{:noreply, do_refresh(socket)}
|
||||
end
|
||||
|
||||
|
||||
defp do_refresh(socket) do
|
||||
players =
|
||||
case CobblemonUi.CobblemonFS.list_players() do
|
||||
@@ -127,7 +126,6 @@ defmodule CobblemonUiWeb.DashboardLive do
|
||||
<Layouts.app flash={@flash}>
|
||||
<div class="h-screen flex flex-col">
|
||||
<div class="max-w-4xl w-full mx-auto px-4 sm:px-6 lg:px-8 flex flex-col flex-1 min-h-0">
|
||||
|
||||
<%!-- Player picker --%>
|
||||
<div :if={is_nil(@selected_player)} class="flex-1 overflow-y-auto py-8">
|
||||
<div class="flex items-center justify-between mb-8">
|
||||
@@ -164,7 +162,10 @@ defmodule CobblemonUiWeb.DashboardLive do
|
||||
<span class="text-base font-semibold text-base-content/80 group-hover:text-base-content truncate">
|
||||
{player.name || "Unknown"}
|
||||
</span>
|
||||
<.icon name="hero-chevron-right" class="size-4 text-base-content/20 ml-auto shrink-0 group-hover:text-primary/40 transition-colors" />
|
||||
<.icon
|
||||
name="hero-chevron-right"
|
||||
class="size-4 text-base-content/20 ml-auto shrink-0 group-hover:text-primary/40 transition-colors"
|
||||
/>
|
||||
</.link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -192,114 +193,117 @@ defmodule CobblemonUiWeb.DashboardLive do
|
||||
|
||||
<%!-- Scrollable content --%>
|
||||
<div class="flex-1 overflow-y-auto py-6">
|
||||
|
||||
<div
|
||||
:if={@error}
|
||||
class="rounded-xl border border-error/30 bg-error/10 px-5 py-4 mb-6"
|
||||
>
|
||||
<div class="flex items-center gap-2 text-error">
|
||||
<.icon name="hero-exclamation-triangle" class="size-5" />
|
||||
<span class="text-sm font-medium">{@error}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :if={@player_data}>
|
||||
<%!-- Stats bar --%>
|
||||
<div class="flex items-center gap-4 text-sm text-base-content/50 mb-6">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="w-2 h-2 rounded-full bg-success/60" />
|
||||
<span>{party_count(@player_data)} in party</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="w-2 h-2 rounded-full bg-info/60" />
|
||||
<span>{pc_count(@player_data)} in PC</span>
|
||||
<div
|
||||
:if={@error}
|
||||
class="rounded-xl border border-error/30 bg-error/10 px-5 py-4 mb-6"
|
||||
>
|
||||
<div class="flex items-center gap-2 text-error">
|
||||
<.icon name="hero-exclamation-triangle" class="size-5" />
|
||||
<span class="text-sm font-medium">{@error}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%!-- Active battle --%>
|
||||
<.battle_panel :if={@battle} battle={@battle} player_id={@selected_player} tier_list={@tier_list} />
|
||||
|
||||
<%!-- View mode tabs --%>
|
||||
<div class="flex items-center gap-1 mb-5 p-1 rounded-lg bg-base-200/40 w-fit">
|
||||
<button
|
||||
id="tab-party"
|
||||
phx-click="switch_view"
|
||||
phx-value-mode="party"
|
||||
class={[
|
||||
"px-4 py-1.5 rounded-md text-sm font-medium transition-all duration-150",
|
||||
if(@view_mode == :party,
|
||||
do: "bg-base-100 text-base-content shadow-sm",
|
||||
else: "text-base-content/50 hover:text-base-content/70"
|
||||
)
|
||||
]}
|
||||
>
|
||||
Party
|
||||
</button>
|
||||
<button
|
||||
id="tab-pc"
|
||||
phx-click="switch_view"
|
||||
phx-value-mode="pc"
|
||||
class={[
|
||||
"px-4 py-1.5 rounded-md text-sm font-medium transition-all duration-150",
|
||||
if(@view_mode == :pc,
|
||||
do: "bg-base-100 text-base-content shadow-sm",
|
||||
else: "text-base-content/50 hover:text-base-content/70"
|
||||
)
|
||||
]}
|
||||
>
|
||||
PC Storage
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<%!-- Party view --%>
|
||||
<div :if={@view_mode == :party}>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||
<%= for {pokemon, idx} <- Enum.with_index(@player_data.party), not is_nil(pokemon) do %>
|
||||
<.pokemon_card
|
||||
pokemon={pokemon}
|
||||
index={idx}
|
||||
tier={Map.get(@tier_list, String.downcase(pokemon.species || ""), nil)}
|
||||
/>
|
||||
<% end %>
|
||||
<div :if={@player_data}>
|
||||
<%!-- Stats bar --%>
|
||||
<div class="flex items-center gap-4 text-sm text-base-content/50 mb-6">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="w-2 h-2 rounded-full bg-success/60" />
|
||||
<span>{party_count(@player_data)} in party</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="w-2 h-2 rounded-full bg-info/60" />
|
||||
<span>{pc_count(@player_data)} in PC</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%!-- PC view --%>
|
||||
<div :if={@view_mode == :pc}>
|
||||
<div :for={box <- @player_data.pc} class="mb-6">
|
||||
<h3 class="text-sm font-semibold text-base-content/50 uppercase tracking-wider mb-3">
|
||||
Box {box.box + 1}
|
||||
</h3>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-5 lg:grid-cols-6 gap-2">
|
||||
<%= for {pokemon, idx} <- Enum.with_index(box.pokemon), not is_nil(pokemon) do %>
|
||||
<%!-- Active battle --%>
|
||||
<.battle_panel
|
||||
:if={@battle}
|
||||
battle={@battle}
|
||||
player_id={@selected_player}
|
||||
tier_list={@tier_list}
|
||||
evolutions={opponent_evolutions(@battle, @selected_player)}
|
||||
/>
|
||||
|
||||
<%!-- View mode tabs --%>
|
||||
<div class="flex items-center gap-1 mb-5 p-1 rounded-lg bg-base-200/40 w-fit">
|
||||
<button
|
||||
id="tab-party"
|
||||
phx-click="switch_view"
|
||||
phx-value-mode="party"
|
||||
class={[
|
||||
"px-4 py-1.5 rounded-md text-sm font-medium transition-all duration-150",
|
||||
if(@view_mode == :party,
|
||||
do: "bg-base-100 text-base-content shadow-sm",
|
||||
else: "text-base-content/50 hover:text-base-content/70"
|
||||
)
|
||||
]}
|
||||
>
|
||||
Party
|
||||
</button>
|
||||
<button
|
||||
id="tab-pc"
|
||||
phx-click="switch_view"
|
||||
phx-value-mode="pc"
|
||||
class={[
|
||||
"px-4 py-1.5 rounded-md text-sm font-medium transition-all duration-150",
|
||||
if(@view_mode == :pc,
|
||||
do: "bg-base-100 text-base-content shadow-sm",
|
||||
else: "text-base-content/50 hover:text-base-content/70"
|
||||
)
|
||||
]}
|
||||
>
|
||||
PC Storage
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<%!-- Party view --%>
|
||||
<div :if={@view_mode == :party}>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||
<%= for {pokemon, idx} <- Enum.with_index(@player_data.party), not is_nil(pokemon) do %>
|
||||
<.pokemon_card
|
||||
pokemon={pokemon}
|
||||
index={pc_global_index(@player_data.pc, box.box, idx)}
|
||||
index={idx}
|
||||
tier={Map.get(@tier_list, String.downcase(pokemon.species || ""), nil)}
|
||||
compact
|
||||
/>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:if={@player_data.pc == []}
|
||||
class="text-center py-12 text-base-content/30 text-sm"
|
||||
>
|
||||
PC storage is empty
|
||||
|
||||
<%!-- PC view --%>
|
||||
<div :if={@view_mode == :pc}>
|
||||
<div :for={box <- @player_data.pc} class="mb-6">
|
||||
<h3 class="text-sm font-semibold text-base-content/50 uppercase tracking-wider mb-3">
|
||||
Box {box.box + 1}
|
||||
</h3>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-5 lg:grid-cols-6 gap-2">
|
||||
<%= for {pokemon, idx} <- Enum.with_index(box.pokemon), not is_nil(pokemon) do %>
|
||||
<.pokemon_card
|
||||
pokemon={pokemon}
|
||||
index={pc_global_index(@player_data.pc, box.box, idx)}
|
||||
tier={Map.get(@tier_list, String.downcase(pokemon.species || ""), nil)}
|
||||
compact
|
||||
/>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:if={@player_data.pc == []}
|
||||
class="text-center py-12 text-base-content/30 text-sm"
|
||||
>
|
||||
PC storage is empty
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%!-- Pokemon detail panel --%>
|
||||
<.pokemon_detail
|
||||
:if={@selected_pokemon}
|
||||
pokemon={@selected_pokemon}
|
||||
tier={Map.get(@tier_list, String.downcase(@selected_pokemon.species || ""), nil)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<%!-- Pokemon detail panel --%>
|
||||
<.pokemon_detail
|
||||
:if={@selected_pokemon}
|
||||
pokemon={@selected_pokemon}
|
||||
tier={Map.get(@tier_list, String.downcase(@selected_pokemon.species || ""), nil)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</Layouts.app>
|
||||
@@ -329,6 +333,24 @@ defmodule CobblemonUiWeb.DashboardLive do
|
||||
end
|
||||
end
|
||||
|
||||
defp opponent_evolutions(nil, _player_id), do: %{}
|
||||
|
||||
defp opponent_evolutions(battle, player_id) do
|
||||
battle.actors
|
||||
|> Enum.reject(fn actor -> actor.player_id == player_id end)
|
||||
|> Enum.flat_map(fn actor -> actor.active_pokemon end)
|
||||
|> Enum.reduce(%{}, fn poke, acc ->
|
||||
species = String.downcase(poke.species || "")
|
||||
|
||||
if species != "" do
|
||||
evolutions = CobblemonUi.EvolutionApi.get_evolutions(species)
|
||||
Map.put(acc, species, evolutions)
|
||||
else
|
||||
acc
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp find_player_battle(uuid) do
|
||||
case CobblemonUi.BattlesApi.list_battles() do
|
||||
{:ok, battles} ->
|
||||
|
||||
Reference in New Issue
Block a user