Refactor currency handling and UI updates
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.
This commit is contained in:
@@ -103,7 +103,7 @@ else
|
||||
<InputNumber class="form-control" @bind-Value="ItemModel.PriceAmount" />
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">Currency</label>
|
||||
<label class="form-label">Currency symbol</label>
|
||||
<InputText class="form-control" @bind-Value="ItemModel.CurrencyCode" />
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
@@ -304,7 +304,7 @@ else
|
||||
<InputDate class="form-control" @bind-Value="SettingsModel.BirthDate" />
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">Currency</label>
|
||||
<label class="form-label">Currency symbol</label>
|
||||
<InputText class="form-control" @bind-Value="SettingsModel.CurrencyCode" />
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
|
||||
@@ -21,11 +21,11 @@ else
|
||||
<div class="card p-3">
|
||||
@if (RepresentableAmounts.Count == 0)
|
||||
{
|
||||
<p class="text-muted mb-0">No representable amount can be formed from configured QR codes up to €200.</p>
|
||||
<p class="text-muted mb-0">No representable amount can be formed from configured QR codes up to @GetCurrencySymbol()200.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<label class="form-label">Select amount: €@SelectedAmount</label>
|
||||
<label class="form-label">Select amount: @GetCurrencySymbol()@SelectedAmount</label>
|
||||
<input type="range"
|
||||
class="form-range"
|
||||
min="0"
|
||||
@@ -45,7 +45,7 @@ else
|
||||
<ul class="mb-3">
|
||||
@foreach (var suggestion in Suggestions)
|
||||
{
|
||||
<li>@suggestion.RepeatCount x €@suggestion.Amount</li>
|
||||
<li>@suggestion.RepeatCount x @GetCurrencySymbol()@suggestion.Amount</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
@@ -55,7 +55,7 @@ else
|
||||
@for (var i = 0; i < suggestion.RepeatCount; i++)
|
||||
{
|
||||
<div>
|
||||
<div class="small mb-1">€@suggestion.Amount</div>
|
||||
<div class="small mb-1">@GetCurrencySymbol()@suggestion.Amount</div>
|
||||
<img src="@BuildQrImageUrl(suggestion.QrCodeUrl)" alt="QR code @suggestion.Amount" class="img-fluid" style="max-height: 220px;" />
|
||||
<div class="small text-muted text-break">
|
||||
<a href="@suggestion.QrCodeUrl" target="_blank" rel="noopener noreferrer">Open payment link</a>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,18 @@ else
|
||||
}
|
||||
@if (item.ParticipationAllowed && GetParticipationTotalAmount(item).HasValue)
|
||||
{
|
||||
<p class="mb-2"><strong>Participation:</strong> €@item.MoneyFulfilledAmount.ToString("0.00") out of €@GetParticipationTotalAmount(item)!.Value.ToString("0.00") fulfilled</p>
|
||||
<p class="mb-2">
|
||||
<strong>Participation:</strong>
|
||||
@item.CurrencyCode@item.MoneyFulfilledAmount.ToString("0.00")
|
||||
@if (GetParticipationTotalAmount(item)!.Value > 0)
|
||||
{
|
||||
<span> out of @item.CurrencyCode@GetParticipationTotalAmount(item)!.Value.ToString("0.00") fulfilled</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span> fulfilled</span>
|
||||
}
|
||||
</p>
|
||||
}
|
||||
|
||||
@if (item.Purchasers.Count > 0 || item.Contributors.Count > 0)
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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<Guid> 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<ContributionAmountQrCodeModel> ParseContributionAmountQrCodes(string? json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var items = JsonSerializer.Deserialize<List<ContributionAmountQrCodeModel>>(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<ContributionAmountQrCodeModel>? 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<IReadOnlyList<RegistryItemEditModel>> 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<ContributionAmountQrCodeModel> ParseContributionAmountQrCodes(string? json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var items = JsonSerializer.Deserialize<List<ContributionAmountQrCodeModel>>(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<ContributionAmountQrCodeModel>? 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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user