fix(Core): updated balance top up instructions

This commit is contained in:
Dmitry Popov
2025-03-14 17:38:31 +01:00
parent b4a1cbbf55
commit a1ffe3cc0e
9 changed files with 254 additions and 1601 deletions

View File

@@ -10,11 +10,21 @@ import { CommentsEditor } from '@/hooks/Mapper/components/mapInterface/component
export const CommentsWidgetContent = () => { export const CommentsWidgetContent = () => {
const { const {
data: { selectedSystems }, data: { selectedSystems, isSubscriptionActive },
} = useMapRootState(); } = useMapRootState();
const isNotSelectedSystem = selectedSystems.length !== 1; const isNotSelectedSystem = selectedSystems.length !== 1;
if (!isSubscriptionActive) {
return (
<div className="w-full h-full flex items-center justify-center">
<span className="select-none text-center text-stone-400/80 text-sm">
Comments available with &#39;Active&#39; map subscription only (contact map administrators)
</span>
</div>
);
}
if (isNotSelectedSystem) { if (isNotSelectedSystem) {
return ( return (
<div className="w-full h-full flex justify-center items-center select-none text-stone-400/80 text-sm"> <div className="w-full h-full flex justify-center items-center select-none text-stone-400/80 text-sm">

File diff suppressed because it is too large Load Diff

View File

@@ -1,115 +0,0 @@
defmodule WandererAppWeb.Components.Pagination do
@moduledoc """
Pagination component for AshPagify.
"""
alias WandererAppWeb.Components
alias AshPagify.Meta
alias AshPagify.Misc
@spec default_opts() :: [Components.pagination_option()]
def default_opts do
[
current_link_attrs: [
class: "pagination-link is-current",
aria: [current: "page"]
],
disabled_class: "disabled",
ellipsis_attrs: [class: "pagination-ellipsis"],
ellipsis_content: Phoenix.HTML.raw("&hellip;"),
next_link_attrs: [
aria: [label: "Go to next page"],
class: "pagination-next"
],
next_link_content: "Next",
page_links: :all,
pagination_link_aria_label: &"Go to page #{&1}",
pagination_link_attrs: [class: "pagination-link"],
previous_link_attrs: [
aria: [label: "Go to previous page"],
class: "pagination-previous"
],
previous_link_content: "Previous",
wrapper_attrs: [
class: "pagination",
role: "navigation",
aria: [label: "pagination"]
]
]
end
def merge_opts(opts) do
default_opts()
|> Misc.list_merge(Misc.global_option(:pagination) || [])
|> Misc.list_merge(opts)
end
def max_pages(:all, total_pages), do: total_pages
def max_pages(:hide, _), do: 0
def max_pages({:ellipsis, max_pages}, _), do: max_pages
def show_pagination(nil), do: false
def show_pagination?(%Meta{errors: [], total_pages: total_pages}) do
total_pages > 1
end
def show_pagination?(_), do: false
def get_page_link_range(current_page, max_pages, total_pages) do
# number of additional pages to show before or after current page
additional = ceil(max_pages / 2)
cond do
max_pages >= total_pages ->
1..total_pages
current_page + additional > total_pages ->
(total_pages - max_pages + 1)..total_pages
true ->
first = max(current_page - additional + 1, 1)
last = min(first + max_pages - 1, total_pages)
first..last
end
end
@spec build_page_link_helper(Meta.t(), Components.pagination_path()) ::
(integer() -> String.t() | nil)
def build_page_link_helper(_meta, nil), do: fn _offset -> nil end
def build_page_link_helper(%Meta{} = meta, path) do
query_params = build_query_params(meta)
fn offset ->
params = maybe_put_offset(query_params, offset)
Components.build_path(path, params)
end
end
defp build_query_params(%Meta{} = meta) do
Components.to_query(meta.ash_pagify, for: meta.resource, default_scopes: meta.default_scopes)
end
defp maybe_put_offset(params, 0), do: Keyword.delete(params, :offset)
defp maybe_put_offset(params, offset), do: Keyword.put(params, :offset, offset)
def attrs_for_page_link(page, %{current_page: page}, opts) do
add_page_link_aria_label(opts[:current_link_attrs], page, opts)
end
def attrs_for_page_link(page, _meta, opts) do
add_page_link_aria_label(opts[:pagination_link_attrs], page, opts)
end
defp add_page_link_aria_label(attrs, page, opts) do
aria_label = opts[:pagination_link_aria_label].(page)
Keyword.update(
attrs,
:aria,
[label: aria_label],
&Keyword.put(&1, :label, aria_label)
)
end
end

View File

@@ -0,0 +1,208 @@
defmodule WandererAppWeb.Maps.MapBalanceComponent do
use WandererAppWeb, :live_component
use LiveViewEvents
require Logger
alias BetterNumber, as: Number
alias WandererApp.License.LicenseManager
@impl true
def mount(socket) do
{:ok,
assign(socket,
is_topping_up?: false,
error: nil
)}
end
@impl true
def update(%{map_id: map_id, current_user: current_user} = assigns, socket) do
socket = handle_info_or_assign(socket, assigns)
{:ok, map} = WandererApp.MapRepo.get(map_id)
{:ok, map_balance} = WandererApp.Map.SubscriptionManager.get_balance(map)
{:ok, user_balance} =
current_user.id
|> WandererApp.User.load()
|> WandererApp.User.get_balance()
socket =
socket
|> assign(assigns)
|> assign(
map_id: map_id,
map: map,
map_balance: map_balance,
user_balance: user_balance,
topup_form: %{} |> to_form()
)
{:ok, socket}
end
@impl true
def handle_event("show_topup", _, socket),
do:
{:noreply,
socket
|> assign(
:amounts,
[
{"150M", 150_000_000},
{"300M", 300_000_000},
{"600M", 600_000_000},
{"1.2B", 1_200_000_000},
{"2.4B", 2_400_000_000},
{"5B", 5_000_000_000}
]
)
|> assign(is_topping_up?: true)}
@impl true
def handle_event("hide_topup", _, socket),
do: {:noreply, socket |> assign(is_topping_up?: false)}
@impl true
def handle_event(
"topup",
%{"amount" => amount} = _event,
%{assigns: %{current_user: current_user, map: map, map_id: map_id}} = socket
) do
amount = amount |> Decimal.new() |> Decimal.to_float()
user =
current_user.id
|> WandererApp.User.load()
{:ok, user_balance} =
user
|> WandererApp.User.get_balance()
case amount <= user_balance do
true ->
{:ok, _t} =
WandererApp.Api.MapTransaction.create(%{
map_id: map_id,
user_id: current_user.id,
amount: amount,
type: :in
})
{:ok, user} =
user
|> WandererApp.Api.User.update_balance(%{
balance: (user_balance || 0.0) - amount
})
{:ok, user_balance} =
user
|> WandererApp.User.get_balance()
{:ok, map_balance} = WandererApp.Map.SubscriptionManager.get_balance(map)
{:noreply,
socket
|> assign(is_topping_up?: false, map_balance: map_balance, user_balance: user_balance)}
_ ->
notify_to(
socket.assigns.notify_to,
socket.assigns.event_name,
{:flash, :error, "You don't have enough ISK on your account balance!"}
)
{:noreply, socket}
end
end
@impl true
def render(assigns) do
~H"""
<div class="map-balance-info">
<div class="stats w-full bg-primary text-primary-content">
<div class="stat">
<div class="stat-title">Account balance</div>
<div class="stat-value text-white">
ISK {@user_balance
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"])}
</div>
<div class="stat-actions text-end"></div>
</div>
<div class="stat">
<div class="stat-figure text-primary">
<.button
:if={not @is_topping_up?}
class="mt-2"
type="button"
phx-click="show_topup"
phx-target={@myself}
>
Top Up
</.button>
</div>
<div class="stat-title">Map balance</div>
<div class="stat-value text-white">
ISK {@map_balance
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"])}
</div>
<div class="stat-actions text-end"></div>
</div>
</div>
<div class="w-full bg-primary">
<h3 class="mt-2 text-2xl font-semibold mb-4 text-white">
How to top up map balance?
</h3>
<ol class="list-decimal list-inside mb-4">
<li class="mb-2">
<strong>Top Up your account balance:</strong>
Click on 'Deposit ISK' button on <a href={~p"/profile"} class="text-purple-400">user profile page</a>.
</li>
<li class="mb-2">
<strong>Wait for account balance updated:</strong>
Check transactions section on
<a href={~p"/profile"} class="text-purple-400">user profile page</a>
</li>
<li class="mb-2">
<strong>Use 'Top Up' button:</strong>
Click on the 'Top Up' button & select the amount you wish to transfer to the map balance.
</li>
<li class="mb-2">
<strong>Accept the transfer:</strong>
Finish the transaction by clicking on the 'Top Up' button.
</li>
</ol>
</div>
<.form
:let={f}
:if={@is_topping_up?}
for={@topup_form}
class="mt-2"
phx-submit="topup"
phx-target={@myself}
>
<.input
type="select"
field={f[:amount]}
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
label="Topup amount"
placeholder="Select topup amount"
options={@amounts}
/>
<div class="modal-action">
<.button class="mt-2" type="button" phx-click="hide_topup" phx-target={@myself}>
Cancel
</.button>
<.button class="mt-2" type="submit">
Top Up
</.button>
</div>
</.form>
</div>
"""
end
end

View File

@@ -25,7 +25,7 @@ defmodule WandererAppWeb.Maps.MapSubscriptionsComponent do
end end
@impl true @impl true
def update(%{map_id: map_id, current_user: current_user} = assigns, socket) do def update(%{map_id: map_id} = assigns, socket) do
socket = handle_info_or_assign(socket, assigns) socket = handle_info_or_assign(socket, assigns)
subscription_form = %{ subscription_form = %{
@@ -217,12 +217,6 @@ defmodule WandererAppWeb.Maps.MapSubscriptionsComponent do
{:flash, :info, "Subscription added!"} {:flash, :info, "Subscription added!"}
) )
notify_to(
socket.assigns.notify_to,
socket.assigns.event_name,
:update_map_balance
)
{:noreply, {:noreply,
socket socket
|> assign( |> assign(
@@ -338,12 +332,6 @@ defmodule WandererAppWeb.Maps.MapSubscriptionsComponent do
{:flash, :info, "Subscription updated!"} {:flash, :info, "Subscription updated!"}
) )
notify_to(
socket.assigns.notify_to,
socket.assigns.event_name,
:update_map_balance
)
{:noreply, {:noreply,
socket socket
|> assign( |> assign(
@@ -464,22 +452,22 @@ defmodule WandererAppWeb.Maps.MapSubscriptionsComponent do
</.button> </.button>
</div> </div>
<.table <.table
class="!max-h-[300px] !overflow-y-auto" class="!max-h-[200px] !overflow-y-auto"
empty_label="No active subscriptions, using alpha plan by default." empty_label="No active subscriptions, using alpha plan by default."
id="active-subscriptions-tbl" id="active-subscriptions-tbl"
rows={@map_subscriptions} rows={@map_subscriptions}
> >
<:col :let={subscription} label="Subscription Plan"> <:col :let={subscription} label="Subscription Plan">
<%= subscription.plan %> {subscription.plan}
</:col> </:col>
<:col :let={subscription} label="Status"> <:col :let={subscription} label="Status">
<%= subscription.status %> {subscription.status}
</:col> </:col>
<:col :let={subscription} label="Characters Limit"> <:col :let={subscription} label="Characters Limit">
<%= subscription.characters_limit %> {subscription.characters_limit}
</:col> </:col>
<:col :let={subscription} label="Hubs Limit"> <:col :let={subscription} label="Hubs Limit">
<%= subscription.hubs_limit %> {subscription.hubs_limit}
</:col> </:col>
<:col :let={subscription} label="Active Till"> <:col :let={subscription} label="Active Till">
<.local_time <.local_time
@@ -487,11 +475,11 @@ defmodule WandererAppWeb.Maps.MapSubscriptionsComponent do
id={"subscription-active-till-#{subscription.id}"} id={"subscription-active-till-#{subscription.id}"}
at={subscription.active_till} at={subscription.active_till}
> >
<%= subscription.active_till %> {subscription.active_till}
</.local_time> </.local_time>
</:col> </:col>
<:col :let={subscription} label="Auto Renew"> <:col :let={subscription} label="Auto Renew">
<%= if subscription.auto_renew?, do: "Yes", else: "No" %> {if subscription.auto_renew?, do: "Yes", else: "No"}
</:col> </:col>
<:action :let={subscription}> <:action :let={subscription}>
<div class="tooltip tooltip-left" data-tip="Edit subscription"> <div class="tooltip tooltip-left" data-tip="Edit subscription">
@@ -581,15 +569,15 @@ defmodule WandererAppWeb.Maps.MapSubscriptionsComponent do
<div> <div>
<div class="stat-title">Estimated price</div> <div class="stat-title">Estimated price</div>
<div class="stat-value text-white"> <div class="stat-value text-white">
ISK <%= (@estimated_price - @discount) ISK {(@estimated_price - @discount)
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %> |> Number.to_human(units: ["", "K", "M", "B", "T", "P"])}
</div> </div>
</div> </div>
<div> <div>
<div class="stat-title">Discount</div> <div class="stat-title">Discount</div>
<div class="stat-value text-white relative"> <div class="stat-value text-white relative">
ISK <%= @discount ISK {@discount
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %> |> Number.to_human(units: ["", "K", "M", "B", "T", "P"])}
<span class="absolute top-0 right-0 text-xs text-white discount" /> <span class="absolute top-0 right-0 text-xs text-white discount" />
</div> </div>
</div> </div>
@@ -611,8 +599,8 @@ defmodule WandererAppWeb.Maps.MapSubscriptionsComponent do
</div> </div>
<div class="stat-title">Additional price (mounthly)</div> <div class="stat-title">Additional price (mounthly)</div>
<div class="stat-value text-white"> <div class="stat-value text-white">
ISK <%= @additional_price ISK {@additional_price
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %> |> Number.to_human(units: ["", "K", "M", "B", "T", "P"])}
</div> </div>
<div class="stat-actions text-end"></div> <div class="stat-actions text-end"></div>
</div> </div>

View File

@@ -103,7 +103,7 @@
<div class="flex flex-col gap-4 w-full"> <div class="flex flex-col gap-4 w-full">
<div class="flex justify-between w-full"> <div class="flex justify-between w-full">
<div /> <div />
<WandererAppWeb.Components.pagination meta={@meta} path={~p"/#{@map_slug}/audit?period=#{@period}&activity=#{@activity}"} /> <AshPagify.Components.pagination meta={@meta} path={~p"/#{@map_slug}/audit?period=#{@period}&activity=#{@activity}"} />
</div> </div>
<.live_component <.live_component
module={UserActivity} module={UserActivity}
@@ -118,7 +118,7 @@
<div class="flex justify-between w-full"> <div class="flex justify-between w-full">
<div /> <div />
<WandererAppWeb.Components.pagination meta={@meta} path={~p"/#{@map_slug}/audit?period=#{@period}&activity=#{@activity}"} /> <AshPagify.Components.pagination meta={@meta} path={~p"/#{@map_slug}/audit?period=#{@period}&activity=#{@activity}"} />
</div> </div>
</div> </div>
</main> </main>

View File

@@ -144,8 +144,6 @@ defmodule WandererAppWeb.MapsLive do
map map
|> WandererApp.Map.Server.get_export_settings() |> WandererApp.Map.Server.get_export_settings()
{:ok, map_balance} = WandererApp.Map.SubscriptionManager.get_balance(map)
{:ok, options_form_data} = WandererApp.MapRepo.options_to_form_data(map) {:ok, options_form_data} = WandererApp.MapRepo.options_to_form_data(map)
socket socket
@@ -165,8 +163,6 @@ defmodule WandererAppWeb.MapsLive do
is_adding_subscription?: false, is_adding_subscription?: false,
selected_subscription: nil, selected_subscription: nil,
options_form: options_form_data |> to_form(), options_form: options_form_data |> to_form(),
map_balance: map_balance,
topup_form: %{} |> to_form(),
layout_options: [ layout_options: [
{"Left To Right", "left_to_right"}, {"Left To Right", "left_to_right"},
{"Top To Bottom", "top_to_bottom"} {"Top To Bottom", "top_to_bottom"}
@@ -322,70 +318,6 @@ defmodule WandererAppWeb.MapsLive do
def handle_event("change_settings_tab", %{"tab" => tab}, socket), def handle_event("change_settings_tab", %{"tab" => tab}, socket),
do: {:noreply, socket |> assign(active_settings_tab: tab)} do: {:noreply, socket |> assign(active_settings_tab: tab)}
@impl true
def handle_event("show_topup", _, socket),
do:
{:noreply,
socket
|> assign(
:amounts,
[
{"150M", 150_000_000},
{"300M", 300_000_000},
{"600M", 600_000_000},
{"1.2B", 1_200_000_000},
{"2.4B", 2_400_000_000},
{"5B", 5_000_000_000}
]
)
|> assign(is_topping_up?: true)}
@impl true
def handle_event("hide_topup", _, socket),
do: {:noreply, socket |> assign(is_topping_up?: false)}
@impl true
def handle_event(
"topup",
%{"amount" => amount} = _event,
%{assigns: %{current_user: current_user, map: map, map_id: map_id}} = socket
) do
amount = amount |> Decimal.new() |> Decimal.to_float()
user =
current_user.id
|> WandererApp.User.load()
{:ok, user_balance} =
user
|> WandererApp.User.get_balance()
case amount <= user_balance do
true ->
{:ok, _t} =
WandererApp.Api.MapTransaction.create(%{
map_id: map_id,
user_id: current_user.id,
amount: amount,
type: :in
})
{:ok, _user} =
user
|> WandererApp.Api.User.update_balance(%{
balance: (user_balance || 0.0) - amount
})
{:ok, map_balance} = WandererApp.Map.SubscriptionManager.get_balance(map)
{:noreply, socket |> assign(is_topping_up?: false, map_balance: map_balance)}
_ ->
{:noreply,
socket |> put_flash(:error, "You don't have enough ISK on your account balance!")}
end
end
def handle_event("open_acl", %{"data" => id}, socket) do def handle_event("open_acl", %{"data" => id}, socket) do
{:noreply, {:noreply,
socket socket
@@ -536,22 +468,12 @@ defmodule WandererAppWeb.MapsLive do
@impl true @impl true
def handle_info( def handle_info(
{"subscriptions_event", {:flash, type, message}}, {_event, {:flash, type, message}},
socket socket
) do ) do
{:noreply, socket |> put_flash(type, message)} {:noreply, socket |> put_flash(type, message)}
end end
@impl true
def handle_info(
{"subscriptions_event", :update_map_balance},
%{assigns: %{map: map}} = socket
)
when not is_nil(map) do
{:ok, map_balance} = WandererApp.Map.SubscriptionManager.get_balance(map)
{:noreply, socket |> assign(map_balance: map_balance)}
end
@impl true @impl true
def handle_info( def handle_info(
{ref, result}, {ref, result},

View File

@@ -531,54 +531,15 @@
</div> </div>
</div> </div>
<div :if={@active_settings_tab == "balance"}> <.live_component
<div class="stats w-full bg-primary text-primary-content"> :if={@active_settings_tab == "balance"}
<div class="stat"> module={WandererAppWeb.Maps.MapBalanceComponent}
<div class="stat-figure text-primary"> id="map-balance-component"
<.button map_id={@map.id}
:if={not @is_topping_up?} notify_to={self()}
class="mt-2" event_name="balance_event"
type="button" current_user={@current_user}
phx-click="show_topup" />
>
<.icon name="hero-banknotes-solid" class="w-4 h-4" /> Top Up
</.button>
</div>
<div class="stat-title">Map balance</div>
<div class="stat-value text-white">
ISK <%= @map_balance
|> Number.to_human(units: ["", "K", "M", "B", "T", "P"]) %>
</div>
<div class="stat-actions text-end"></div>
</div>
</div>
<.form
:let={f}
:if={@is_topping_up?}
for={@topup_form}
class="mt-2"
phx-change="validate_topup"
phx-submit="topup"
>
<.input
type="select"
field={f[:amount]}
class="select h-8 min-h-[10px] !pt-1 !pb-1 text-sm bg-neutral-900"
label="Topup amount"
placeholder="Select topup amount"
options={@amounts}
/>
<div class="modal-action">
<.button class="mt-2" type="button" phx-click="hide_topup">
Cancel
</.button>
<.button class="mt-2" type="submit">
Top Up
</.button>
</div>
</.form>
</div>
<.live_component <.live_component
:if={@active_settings_tab == "subscription"} :if={@active_settings_tab == "subscription"}

View File

@@ -15,7 +15,7 @@
<div class="card dark:bg-zinc-800 dark:border-zinc-600"> <div class="card dark:bg-zinc-800 dark:border-zinc-600">
<div class="card-body"> <div class="card-body">
<div class="col-span-6"> <div class="col-span-6">
<span class="text-gray-700 dark:text-gray-400">Wanderer Balance</span> <span class="text-gray-700 dark:text-gray-400">Account Balance</span>
<h4 class="mt-4 font-medium text-gray-800 text-4xl dark:text-gray-100"> <h4 class="mt-4 font-medium text-gray-800 text-4xl dark:text-gray-100">
<span class="counter-value"> <span class="counter-value">
ISK <%= @wanderer_balance ISK <%= @wanderer_balance
@@ -308,27 +308,24 @@
</h2> </h2>
<ol class="list-decimal list-inside mb-4"> <ol class="list-decimal list-inside mb-4">
<li class="mb-2"> <li class="mb-2">
<strong>Open Your Wallet:</strong> <strong>Open corporations overview:</strong>
Click on the wallet icon in the Neocom menu to access your financial overview. Click on the 'Social' and then on 'Corporation' in the Neocom menu to access corporations search.
</li> </li>
<li class="mb-2"> <li class="mb-2">
<strong>Navigate to the 'Transfer ISK' Tab:</strong> <strong>Search for a Corporation:</strong>
Find the 'Transfer ISK' option in your wallet interface. Type in the search bar the name: <b><%= @corporation_info["name"] %></b>.
</li> </li>
<li class="mb-2"> <li class="mb-2">
<strong>Choose 'Give ISK':</strong> <strong>Choose 'Give Money':</strong>
Click on the 'Give ISK' button to initiate the transfer. Select the 'Give Money' in the context menu to initiate the transfer.
</li>
<li class="mb-2">
<strong>Enter Recipient's Name:</strong>
Type in the name of the Wanderer name: <b><%= @corporation_info["name"] %></b>.
</li> </li>
<li class="mb-2"> <li class="mb-2">
<strong>Specify the Amount:</strong> <strong>Specify the Amount:</strong>
Input the amount of ISK you wish to transfer to the corporate account. Input the amount of ISK you wish to transfer to the corporate account.
</li> </li>
<li class="mb-2"> <li class="mb-2">
<strong>Add a Note (Optional):</strong> <strong>Add a Reason (Optional):</strong>
Include a short note or reason for the transfer if desired. Include a short note or reason for the transfer if desired.
</li> </li>
<li class="mb-2"> <li class="mb-2">