Skip to content

Commit

Permalink
Add fiat currency to display toggle
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisreimann committed Jan 31, 2025
1 parent 68137f9 commit 7140432
Show file tree
Hide file tree
Showing 20 changed files with 205 additions and 151 deletions.
41 changes: 32 additions & 9 deletions BTCPayApp.UI/Components/AmountDisplay.razor
Original file line number Diff line number Diff line change
@@ -1,27 +1,50 @@
@using BTCPayApp.UI.Util
@using NBitcoin

@inject DisplayFormatter DisplayFormatter

<span @onclick="ToggleDisplayCurrency" @onclick:stopPropagation class="@CssClass">@DisplayFormatter.Currency(Value, Unit, DisplayFormatter.CurrencyFormat.Symbol)</span>
<span @attributes="InputAttributes" @onclick="ChangeDisplayCurrency" @onclick:stopPropagation class="@CssClass">
@DisplayValue
</span>

@code {
[Parameter, EditorRequired]
public required decimal Value { get; set; }
public required long Sats { get; set; }

[Parameter, EditorRequired]
public required string Unit { get; set; }
public required string Currency { get; set; }

[Parameter]
public EventCallback OnToggleDisplayCurrency { get; set; }
public decimal? Rate { get; set; }

[Parameter]
public EventCallback OnChangeDisplayCurrency { get; set; }

[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object>? InputAttributes { get; set; }

private string? CssClass => InputAttributes?.ContainsKey("class") is true ? InputAttributes["class"].ToString() : null;

private async Task ToggleDisplayCurrency()
private async Task ChangeDisplayCurrency()
{
if (OnToggleDisplayCurrency.HasDelegate)
await OnToggleDisplayCurrency.InvokeAsync();
if (OnChangeDisplayCurrency.HasDelegate)
await OnChangeDisplayCurrency.InvokeAsync();
}

private bool CanDisplayFiat => !string.IsNullOrEmpty(Currency) && DisplayFormatter.HasCurrency(Currency) && Rate.HasValue;
private decimal Btc => new Money(Sats, MoneyUnit.Satoshi).ToDecimal(MoneyUnit.BTC);
private string CurrencyUnit => Currency switch
{
CurrencyDisplay.BTC => CurrencyDisplay.BTC,
CurrencyDisplay.SATS => CurrencyDisplay.SATS,
_ => CanDisplayFiat
? Currency
: CurrencyDisplay.SATS
};
private decimal CurrencyValue => CurrencyUnit switch
{
CurrencyDisplay.SATS => Sats,
CurrencyDisplay.BTC => Btc,
_ => CanDisplayFiat ? Btc * Rate!.Value : Sats
};
private string DisplayValue => DisplayFormatter.Currency(CurrencyValue, CurrencyUnit, DisplayFormatter.CurrencyFormat.Symbol);
private string? CssClass => InputAttributes?.ContainsKey("class") is true ? InputAttributes["class"].ToString() : null;
}
4 changes: 3 additions & 1 deletion BTCPayApp.UI/Components/AppItemsEditor.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@using Plk.Blazor.DragDrop
@inject IJSRuntime JS
@inject IAccountManager AccountManager
@inject DisplayFormatter DisplayFormatter
@inject IDataDirectoryProvider DataDirectoryProvider

<div @attributes="InputAttributes" class="@CssClass">
Expand Down Expand Up @@ -35,7 +36,8 @@
else if (context.Price.HasValue)
{
<span class="fw-semibold text-muted">
<AmountDisplay Value="@context.Price.Value" Unit="@Currency"/> @(context.PriceType == AppItemPriceType.Minimum ? " minimum" : null)
@DisplayFormatter.Currency(context.Price.Value, Currency, DisplayFormatter.CurrencyFormat.Symbol)
@(context.PriceType == AppItemPriceType.Minimum ? " minimum" : null)
</span>
}
@if (context.Inventory.HasValue)
Expand Down
8 changes: 5 additions & 3 deletions BTCPayApp.UI/Components/LightningPaymentItem.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<div>
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2" @onclick="() => _showDetails = !_showDetails">
<AmountDisplay Value="Payment.Value!.ToDecimal(UnitLightMoney)" Unit="@Unit" OnToggleDisplayCurrency="ToggleDisplayCurrency" class="text-end fw-semibold" />
<AmountDisplay Sats="Payment.Value!.MilliSatoshi / 1000" Rate="@Rate" Currency="@Currency" OnChangeDisplayCurrency="ToggleDisplayCurrency" class="text-end fw-semibold" />
<span class="text-muted">
<DateDisplay DateTimeOffset="@Payment.Timestamp"/>
</span>
Expand Down Expand Up @@ -36,7 +36,10 @@
public AppLightningPayment Payment { get; set; } = null!;

[Parameter, EditorRequired]
public string? Unit { get; set; }
public string? Currency { get; set; }

[Parameter]
public decimal? Rate { get; set; }

[Parameter]
public EventCallback<AppLightningPayment> OnCancelClick { get; set; }
Expand All @@ -45,7 +48,6 @@
public EventCallback OnToggleDisplayCurrency { get; set; }

private bool _showDetails;
private LightMoneyUnit UnitLightMoney => Unit == "SATS" ? LightMoneyUnit.Satoshi : LightMoneyUnit.BTC;

private async Task ToggleDisplayCurrency()
{
Expand Down
7 changes: 5 additions & 2 deletions BTCPayApp.UI/Components/LightningPaymentList.razor
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@foreach (var p in Payments)
{
<div class="box">
<LightningPaymentItem Payment="@p" Unit="@Unit" OnCancelClick="OnCancelClick" OnToggleDisplayCurrency="OnToggleDisplayCurrency"/>
<LightningPaymentItem Payment="@p" Rate="@Rate" Currency="@Currency" OnCancelClick="OnCancelClick" OnToggleDisplayCurrency="OnToggleDisplayCurrency"/>
</div>
}
}
Expand All @@ -35,7 +35,10 @@
public IEnumerable<AppLightningPayment>? Payments { get; set; }

[Parameter, EditorRequired]
public string? Unit { get; set; }
public string? Currency { get; set; }

[Parameter]
public decimal? Rate { get; set; }

[Parameter]
public EventCallback<AppLightningPayment> OnCancelClick { get; set; }
Expand Down
7 changes: 5 additions & 2 deletions BTCPayApp.UI/Components/TransactionsList.razor
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@foreach (var t in Transactions)
{
<div class="box">
<TransactionsListItem Transaction="@t" Unit="@Unit" OnToggleDisplayCurrency="OnToggleDisplayCurrency"/>
<TransactionsListItem Transaction="@t" Rate="@Rate" Currency="@Currency" OnToggleDisplayCurrency="OnToggleDisplayCurrency"/>
</div>
}
}
Expand All @@ -35,7 +35,10 @@
public IEnumerable<TransactionModel>? Transactions { get; set; }

[Parameter, EditorRequired]
public string? Unit { get; set; }
public string? Currency { get; set; }

[Parameter]
public decimal? Rate { get; set; }

[Parameter]
public EventCallback OnToggleDisplayCurrency { get; set; }
Expand Down
8 changes: 5 additions & 3 deletions BTCPayApp.UI/Components/TransactionsListItem.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<span class="flex-grow-1 text-muted">
<DateDisplay DateTimeOffset="@Transaction.Timestamp"/>
</span>
<AmountDisplay Value="Transaction.Value.ToDecimal(UnitLightMoney)" Unit="@Unit" OnToggleDisplayCurrency="ToggleDisplayCurrency" class="@AmountClass" />
<AmountDisplay Sats="Transaction.Value.MilliSatoshi / 1000" Rate="@Rate" Currency="@Currency" OnChangeDisplayCurrency="ToggleDisplayCurrency" class="@AmountClass" />
<span class="w-100px ms-auto text-end">
<span class="@BadgeClass">@UnifyStatus(Transaction.Status)</span>
</span>
Expand Down Expand Up @@ -52,13 +52,15 @@
public TransactionModel Transaction { get; set; } = null!;

[Parameter, EditorRequired]
public string? Unit { get; set; }
public string? Currency { get; set; }

[Parameter]
public decimal? Rate { get; set; }

[Parameter]
public EventCallback OnToggleDisplayCurrency { get; set; }

private bool _showDetails;
private LightMoneyUnit UnitLightMoney => Unit == "SATS" ? LightMoneyUnit.Satoshi : LightMoneyUnit.BTC;
private string AmountClass => $"flex-grow-1 text-end fw-semibold text-{(Transaction.Type == TransactionType.Receive ? "success" : "danger")}";
private string BadgeClass
{
Expand Down
26 changes: 7 additions & 19 deletions BTCPayApp.UI/Components/WalletOverview.razor
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
@using BTCPayApp.UI.Util
@using BTCPayServer.Client.Models
@using NBitcoin
@implements IDisposable
@inject IJSRuntime JS
@inject DisplayFormatter DisplayFormatter

<div @attributes="InputAttributes" class="@CssClass">
@if (BitcoinBalance != null)
@if (Sats != null)
{
<div class="amount text-center">
<AmountDisplay Value="BitcoinBalance.Value" Unit="@BitcoinUnit" OnToggleDisplayCurrency="HandleBalanceClick" class="sats fw-bold fs-1" />
@if (Loading is true)
@if (Sats.HasValue)
{
<div class="text-muted"><LoadingIndicator/></div>
<AmountDisplay Sats="Sats.Value" Rate="@Rate" Currency="@Currency" OnChangeDisplayCurrency="HandleBalanceClick" class="fw-bold fs-1" />
}
else if (CurrencyValue.HasValue)
else if (Loading is true)
{
<div class="fiat fw-semibold text-muted">~ @DisplayFormatter.Currency(CurrencyValue.Value, Currency!, DisplayFormatter.CurrencyFormat.Symbol)</div>
<LoadingIndicator/>
}
</div>
}
Expand All @@ -31,13 +29,7 @@

@code {
[Parameter]
public decimal? BitcoinBalance { get; set; }

[Parameter]
public string? BitcoinUnit { get; set; }

[Parameter]
public MoneyUnit MoneyUnit { get; set; }
public long? Sats { get; set; }

[Parameter]
public HistogramData? Histogram { get; set; }
Expand All @@ -60,10 +52,6 @@
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object>? InputAttributes { get; set; }

private decimal? CurrencyValue => BitcoinBalance != null && Rate.HasValue && !string.IsNullOrEmpty(Currency)
? new Money(BitcoinBalance.Value, MoneyUnit).ToDecimal(MoneyUnit.BTC) * Rate.Value
: null;

private async Task HandleBalanceClick()
{
if (OnBalanceClick.HasDelegate)
Expand All @@ -73,7 +61,7 @@
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (Histogram != null)
await JS.InvokeVoidAsync("Chart.renderLineChart", "#Histogram", Histogram.Labels, Histogram.Series, Histogram.Type.ToString(), "BTC", BitcoinUnit, null, Currency);
await JS.InvokeVoidAsync("Chart.renderLineChart", "#Histogram", Histogram.Labels, Histogram.Series, Histogram.Type.ToString(), "BTC", Rate, Currency);
}

public void Dispose()
Expand Down
8 changes: 6 additions & 2 deletions BTCPayApp.UI/Features/StoreState.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BTCPayApp.Core.Auth;
using BTCPayApp.Core.Models;
using BTCPayApp.UI.Util;
using BTCPayServer.Client.Models;
using Fluxor;

Expand Down Expand Up @@ -27,7 +28,7 @@ public record StoreState
public HistogramData? UnifiedHistogram;
public HistogramType? HistogramType;

private static string[] RateFetchExcludes = ["BTC", "SATS"];
private static readonly string[] BitcoinUnits = [CurrencyDisplay.BTC, CurrencyDisplay.SATS];

public record SetStoreInfo(AppUserStoreInfo? StoreInfo);
public record SetHistogramType(HistogramType Type);
Expand Down Expand Up @@ -640,6 +641,9 @@ public Task SetStoreInfoEffect(SetStoreInfo action, IDispatcher dispatcher)
dispatcher.Dispatch(new FetchRates(store));
dispatcher.Dispatch(new FetchPointOfSale(posId));
dispatcher.Dispatch(new FetchPointOfSaleStats(posId));

var currency = BitcoinUnits.Contains(store.DefaultCurrency) ? null : store.DefaultCurrency;
dispatcher.Dispatch(new UIState.SetFiatCurrency(currency));
}
return Task.CompletedTask;
}
Expand Down Expand Up @@ -883,7 +887,7 @@ public async Task FetchPosSalesStatsEffect(FetchPosSalesStats action, IDispatche
public async Task FetchRatesEffect(FetchRates action, IDispatcher dispatcher)
{
var currency = action.Store.DefaultCurrency;
if (RateFetchExcludes.Contains(currency)) return;
if (BitcoinUnits.Contains(currency)) return;
try
{
var rates = await accountManager.GetClient().GetStoreRates(action.Store.Id, [$"BTC_{currency}"]);
Expand Down
54 changes: 30 additions & 24 deletions BTCPayApp.UI/Features/UIState.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
using System.Text.Json.Serialization;
using BTCPayApp.Core;
using BTCPayApp.Core.Models;
using BTCPayApp.UI.Util;
using BTCPayServer.Client.Models;
using Fluxor;
using Microsoft.JSInterop;

namespace BTCPayApp.UI.Features;

public static class Themes
{
public const string Dark = "dark";
public const string Light = "light";
public const string System = "system";
}

public static class CurrencyUnit
{
public const string SATS = "SATS";
public const string BTC = "BTC";
}

[FeatureState]
public record UIState
{
public string SelectedTheme { get; set; } = Themes.System;
public string SystemTheme { get; set; } = Themes.Light;
public string BitcoinUnit { get; set; } = CurrencyUnit.SATS;
public string DisplayCurrency { get; set; } = CurrencyDisplay.SATS;
public string? FiatCurrency { get; set; }
public HistogramType HistogramType { get; set; } = HistogramType.Week;

[JsonIgnore]
Expand All @@ -35,9 +24,12 @@ public record ApplyUserTheme(string Theme);
public record SetUserTheme(string Theme);
public record FetchInstanceInfo(string? Url);
public record SetInstanceInfo(AppInstanceInfo? Instance, string? Error);
public record ToggleBitcoinUnit(string? BitcoinUnit = null);
public record ToggleDisplayCurrency(string? Currency = null);
public record SetFiatCurrency(string? Currency = null);
public record SetHistogramType(HistogramType Type);

public bool IsDarkMode => SelectedTheme == Themes.System? SystemTheme == Themes.Dark : SelectedTheme == Themes.Dark;

protected class SetUserThemeReducer : Reducer<UIState, SetUserTheme>
{
public override UIState Reduce(UIState state, SetUserTheme action)
Expand All @@ -50,7 +42,16 @@ public override UIState Reduce(UIState state, SetUserTheme action)
}
}

public bool IsDarkMode => SelectedTheme == Themes.System? SystemTheme == Themes.Dark : SelectedTheme == Themes.Dark;
protected class SetFiatCurrencyReducer : Reducer<UIState, SetFiatCurrency>
{
public override UIState Reduce(UIState state, SetFiatCurrency action)
{
return state with
{
FiatCurrency = action.Currency
};
}
}

protected class FetchInstanceInfoReducer : Reducer<UIState, FetchInstanceInfo>
{
Expand Down Expand Up @@ -82,16 +83,21 @@ public override UIState Reduce(UIState state, SetInstanceInfo action)
}
}

protected class ToggleBitcoinUnitReducer : Reducer<UIState, ToggleBitcoinUnit>
protected class ToggleDisplayCurrencyReducer : Reducer<UIState, ToggleDisplayCurrency>
{
public override UIState Reduce(UIState state, ToggleBitcoinUnit action)
public override UIState Reduce(UIState state, ToggleDisplayCurrency action)
{
var unit = action.BitcoinUnit ?? (state.BitcoinUnit == CurrencyUnit.SATS
? CurrencyUnit.BTC
: CurrencyUnit.SATS);
var unit = action.Currency ?? state.DisplayCurrency switch
{
CurrencyDisplay.BTC => CurrencyDisplay.SATS,
CurrencyDisplay.SATS => string.IsNullOrEmpty(state.FiatCurrency)
? CurrencyDisplay.BTC
: state.FiatCurrency,
_ => CurrencyDisplay.BTC
};
return state with
{
BitcoinUnit = unit
DisplayCurrency = unit
};
}
}
Expand Down Expand Up @@ -148,9 +154,9 @@ public async Task SetInstanceInfoEffect(SetInstanceInfo action, IDispatcher disp
}

[EffectMethod]
public async Task ToggleBitcoinUnitEffect(ToggleBitcoinUnit action, IDispatcher dispatcher)
public async Task ToggleDisplayCurrencyEffect(ToggleDisplayCurrency action, IDispatcher dispatcher)
{
await jsRuntime.InvokeVoidAsync("Interop.setBitcoinUnit", state.Value.BitcoinUnit);
await jsRuntime.InvokeVoidAsync("Interop.setBitcoinUnit", state.Value.DisplayCurrency);
}

[EffectMethod]
Expand Down
Loading

0 comments on commit 7140432

Please sign in to comment.