From 9f3ae1051c89f29dde65266d007072e799bb5e62 Mon Sep 17 00:00:00 2001 From: Arne Moerman Date: Tue, 19 May 2026 22:05:10 +0200 Subject: [PATCH] Refactor currency handling and UI updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated currency handling to use dynamic symbols, defaulting to "€". Adjusted UI components to reflect these changes. Introduced `GetCurrencySymbol` and `NormalizeCurrencySymbol` methods for consistency. Reintroduced QR code parsing/serialization methods. Updated models and services to align with the new currency symbol logic. --- .../Components/Pages/RegistryAdmin.razor | 4 +- .../Pages/RegistryContributionAmount.razor | 8 +- .../Pages/RegistryContributionAmount.razor.cs | 7 + .../Components/Pages/RegistryPublic.razor | 13 +- .../Features/Registries/RegistryModels.cs | 8 +- .../Features/Registries/RegistryService.cs | 126 ++++++++++-------- 6 files changed, 96 insertions(+), 70 deletions(-) diff --git a/src/BirthList.Web/Components/Pages/RegistryAdmin.razor b/src/BirthList.Web/Components/Pages/RegistryAdmin.razor index 8e53d72..f3d2f7c 100644 --- a/src/BirthList.Web/Components/Pages/RegistryAdmin.razor +++ b/src/BirthList.Web/Components/Pages/RegistryAdmin.razor @@ -103,7 +103,7 @@ else
- +
@@ -304,7 +304,7 @@ else
- +
diff --git a/src/BirthList.Web/Components/Pages/RegistryContributionAmount.razor b/src/BirthList.Web/Components/Pages/RegistryContributionAmount.razor index 1928ca7..dc962de 100644 --- a/src/BirthList.Web/Components/Pages/RegistryContributionAmount.razor +++ b/src/BirthList.Web/Components/Pages/RegistryContributionAmount.razor @@ -21,11 +21,11 @@ else
@if (RepresentableAmounts.Count == 0) { -

No representable amount can be formed from configured QR codes up to €200.

+

No representable amount can be formed from configured QR codes up to @GetCurrencySymbol()200.

} else { - + @foreach (var suggestion in Suggestions) { -
  • @suggestion.RepeatCount x €@suggestion.Amount
  • +
  • @suggestion.RepeatCount x @GetCurrencySymbol()@suggestion.Amount
  • } @@ -55,7 +55,7 @@ else @for (var i = 0; i < suggestion.RepeatCount; i++) {
    -
    €@suggestion.Amount
    +
    @GetCurrencySymbol()@suggestion.Amount
    QR code @suggestion.Amount
    Open payment link diff --git a/src/BirthList.Web/Components/Pages/RegistryContributionAmount.razor.cs b/src/BirthList.Web/Components/Pages/RegistryContributionAmount.razor.cs index d10b89e..3cf955f 100644 --- a/src/BirthList.Web/Components/Pages/RegistryContributionAmount.razor.cs +++ b/src/BirthList.Web/Components/Pages/RegistryContributionAmount.razor.cs @@ -207,4 +207,11 @@ public partial class RegistryContributionAmount : ComponentBase public string QrCodeUrl { get; init; } = string.Empty; public int RepeatCount { get; init; } } + + protected string GetCurrencySymbol() + { + return string.IsNullOrWhiteSpace(Registry?.CurrencyCode) + ? "€" + : Registry.CurrencyCode; + } } diff --git a/src/BirthList.Web/Components/Pages/RegistryPublic.razor b/src/BirthList.Web/Components/Pages/RegistryPublic.razor index e5407de..a4773a3 100644 --- a/src/BirthList.Web/Components/Pages/RegistryPublic.razor +++ b/src/BirthList.Web/Components/Pages/RegistryPublic.razor @@ -87,7 +87,18 @@ else } @if (item.ParticipationAllowed && GetParticipationTotalAmount(item).HasValue) { -

    Participation: €@item.MoneyFulfilledAmount.ToString("0.00") out of €@GetParticipationTotalAmount(item)!.Value.ToString("0.00") fulfilled

    +

    + Participation: + @item.CurrencyCode@item.MoneyFulfilledAmount.ToString("0.00") + @if (GetParticipationTotalAmount(item)!.Value > 0) + { + out of @item.CurrencyCode@GetParticipationTotalAmount(item)!.Value.ToString("0.00") fulfilled + } + else + { + fulfilled + } +

    } @if (item.Purchasers.Count > 0 || item.Contributors.Count > 0) diff --git a/src/BirthList.Web/Features/Registries/RegistryModels.cs b/src/BirthList.Web/Features/Registries/RegistryModels.cs index ae79153..73daa0e 100644 --- a/src/BirthList.Web/Features/Registries/RegistryModels.cs +++ b/src/BirthList.Web/Features/Registries/RegistryModels.cs @@ -31,7 +31,7 @@ public sealed class RegistryItemEditModel public string? ProductUrl { get; set; } public string? Description { get; set; } public decimal? PriceAmount { get; set; } - public string CurrencyCode { get; set; } = "EUR"; + public string CurrencyCode { get; set; } = "€"; public int DesiredQuantity { get; set; } = 1; public bool ParticipationAllowed { get; set; } public decimal? ParticipationTargetAmount { get; set; } @@ -55,7 +55,7 @@ public sealed class RegistrySettingsEditModel public DateOnly? BirthDate { get; set; } public string? HeaderContentHtml { get; set; } public string? ShippingAddress { get; set; } - public string CurrencyCode { get; set; } = "EUR"; + public string CurrencyCode { get; set; } = "€"; public string ThemeKey { get; set; } = "default"; public string? BankAccountIban { get; set; } public string? BankAccountBic { get; set; } @@ -82,7 +82,7 @@ public sealed class RegistryPublicViewModel public string? BabyName { get; init; } public string? HeaderContentHtml { get; init; } public string? ShippingAddress { get; init; } - public string CurrencyCode { get; init; } = "EUR"; + public string CurrencyCode { get; init; } = "€"; public string ThemeKey { get; init; } = "default"; public RegistryType RegistryType { get; init; } public string? BankAccountIban { get; init; } @@ -117,7 +117,7 @@ public sealed class RegistryPublicItemViewModel public string? ProductUrl { get; init; } public string? Description { get; init; } public decimal? PriceAmount { get; init; } - public string CurrencyCode { get; init; } = "EUR"; + public string CurrencyCode { get; init; } = "€"; public int DesiredQuantity { get; init; } public int PurchasedQuantity { get; init; } public bool ParticipationAllowed { get; init; } diff --git a/src/BirthList.Web/Features/Registries/RegistryService.cs b/src/BirthList.Web/Features/Registries/RegistryService.cs index e69a122..bc4d043 100644 --- a/src/BirthList.Web/Features/Registries/RegistryService.cs +++ b/src/BirthList.Web/Features/Registries/RegistryService.cs @@ -11,6 +11,7 @@ namespace BirthList.Web.Features.Registries; internal sealed class RegistryService(RegistryDbContext registryDbContext, ApplicationDbContext applicationDbContext) { private const string DefaultCategoryName = "General"; + private const string DefaultCurrencySymbol = "€"; public async Task CreateRegistryAsync(string userId, RegistryCreateModel model, CancellationToken cancellationToken) { @@ -31,7 +32,7 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli ThemeKey = string.IsNullOrWhiteSpace(model.ThemeKey) ? "default" : model.ThemeKey.Trim(), PublicLinkCode = publicCode, CreatedAtUtc = DateTimeOffset.UtcNow, - CurrencyCode = "EUR" + CurrencyCode = DefaultCurrencySymbol }; registryDbContext.Registries.Add(registry); @@ -373,7 +374,7 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli registry.BirthDate = model.BirthDate; registry.HeaderContentHtml = string.IsNullOrWhiteSpace(model.HeaderContentHtml) ? null : model.HeaderContentHtml; registry.ShippingAddress = string.IsNullOrWhiteSpace(model.ShippingAddress) ? null : model.ShippingAddress.Trim(); - registry.CurrencyCode = string.IsNullOrWhiteSpace(model.CurrencyCode) ? "EUR" : model.CurrencyCode.Trim().ToUpperInvariant(); + registry.CurrencyCode = NormalizeCurrencySymbol(model.CurrencyCode); registry.ThemeKey = string.IsNullOrWhiteSpace(model.ThemeKey) ? "default" : model.ThemeKey.Trim(); settings.BankAccountIban = string.IsNullOrWhiteSpace(model.BankAccountIban) ? null : model.BankAccountIban.Trim(); @@ -386,62 +387,6 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli await registryDbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } - private static IReadOnlyList ParseContributionAmountQrCodes(string? json) - { - if (string.IsNullOrWhiteSpace(json)) - { - return []; - } - - try - { - var items = JsonSerializer.Deserialize>(json); - if (items is null) - { - return []; - } - - return items - .Where(x => x.Amount > 0 && !string.IsNullOrWhiteSpace(x.QrCodeUrl)) - .Select(x => new ContributionAmountQrCodeModel - { - Amount = x.Amount, - QrCodeUrl = x.QrCodeUrl.Trim() - }) - .OrderBy(x => x.Amount) - .ToList(); - } - catch (JsonException) - { - return []; - } - } - - private static string? SerializeContributionAmountQrCodes(IEnumerable? amountQrCodes) - { - if (amountQrCodes is null) - { - return null; - } - - var normalized = amountQrCodes - .Where(x => x.Amount > 0 && !string.IsNullOrWhiteSpace(x.QrCodeUrl)) - .Select(x => new ContributionAmountQrCodeModel - { - Amount = x.Amount, - QrCodeUrl = x.QrCodeUrl.Trim() - }) - .OrderBy(x => x.Amount) - .ToList(); - - if (normalized.Count == 0) - { - return null; - } - - return JsonSerializer.Serialize(normalized); - } - public async Task> GetRegistryItemsAsync(Guid registryId, CancellationToken cancellationToken) { var defaultCategory = await EnsureDefaultCategoryAsync(registryId, cancellationToken).ConfigureAwait(false); @@ -682,7 +627,7 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli entity.ProductUrl = string.IsNullOrWhiteSpace(model.ProductUrl) ? null : model.ProductUrl.Trim(); entity.Description = string.IsNullOrWhiteSpace(model.Description) ? null : model.Description.Trim(); entity.PriceAmount = model.PriceAmount; - entity.CurrencyCode = string.IsNullOrWhiteSpace(model.CurrencyCode) ? "EUR" : model.CurrencyCode.Trim().ToUpperInvariant(); + entity.CurrencyCode = NormalizeCurrencySymbol(model.CurrencyCode); entity.DesiredQuantity = model.DesiredQuantity < 1 ? 1 : model.DesiredQuantity; entity.ParticipationAllowed = model.ParticipationAllowed; entity.ParticipationTargetAmount = model.ParticipationAllowed ? model.ParticipationTargetAmount : null; @@ -1629,4 +1574,67 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli await registryDbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } } + + private static IReadOnlyList ParseContributionAmountQrCodes(string? json) + { + if (string.IsNullOrWhiteSpace(json)) + { + return []; + } + + try + { + var items = JsonSerializer.Deserialize>(json); + if (items is null) + { + return []; + } + + return items + .Where(x => x.Amount > 0 && !string.IsNullOrWhiteSpace(x.QrCodeUrl)) + .Select(x => new ContributionAmountQrCodeModel + { + Amount = x.Amount, + QrCodeUrl = x.QrCodeUrl.Trim() + }) + .OrderBy(x => x.Amount) + .ToList(); + } + catch (JsonException) + { + return []; + } + } + + private static string? SerializeContributionAmountQrCodes(IEnumerable? amountQrCodes) + { + if (amountQrCodes is null) + { + return null; + } + + var normalized = amountQrCodes + .Where(x => x.Amount > 0 && !string.IsNullOrWhiteSpace(x.QrCodeUrl)) + .Select(x => new ContributionAmountQrCodeModel + { + Amount = x.Amount, + QrCodeUrl = x.QrCodeUrl.Trim() + }) + .OrderBy(x => x.Amount) + .ToList(); + + if (normalized.Count == 0) + { + return null; + } + + return JsonSerializer.Serialize(normalized); + } + + private static string NormalizeCurrencySymbol(string? currencySymbol) + { + return string.IsNullOrWhiteSpace(currencySymbol) + ? DefaultCurrencySymbol + : currencySymbol.Trim(); + } }