GuestLog - Integrated AddressQuery dialog in GuestDocument creation and fixes.

- Added new CountryCodeUtils to map ISO-3166:Alpha2 country codes to ISO-3166:Alpha3 codes.
- Added new config for results language of AddressQuery services.
This commit is contained in:
2026-08-11 22:02:15 +02:00
parent 5c7fed2677
commit 8232e7d7c9
8 changed files with 466 additions and 43 deletions
@@ -5,23 +5,24 @@
@inject IAddressQueryFactory addressQueryFactory;
@inject ISnackbar Snackbar
<MudDialog>
<MudDialog @ref="@DialogRef">
<TitleContent>
<MudText Typo="Typo.h6">
<MudIcon Icon="@Icons.Material.Filled.NotListedLocation" Class="mr-3 mb-n1" />
Search Address
@LanguageLocale.control_AddressQueryDialog_dialogTitle
</MudText>
</TitleContent>
<DialogContent>
<MudStack row>
<MudTextField @ref="txtSearch" @bind-Value="SearchText" Label="Search address" Required />
<MudTextField @bind-Value="SearchText" Label="@LanguageLocale.control_AddressQueryDialog_searchText"
Required />
<MudIconButton Icon="@Icons.Material.Filled.Search" OnClick="btnSearchAddress" />
</MudStack>
<MudPaper Class="mt-4 pa-2">
@if (addressResults.Count == 0)
{
<MudText Typo="Typo.body1">No results!</MudText>
<MudText Typo="Typo.body1">@LanguageLocale.general_noResults</MudText>
}
<MudList T="AddressResultDTO" @bind-SelectedValue="SelectedAddressResult"
@@ -30,16 +31,21 @@
{
<MudListItem Value="result">
<ChildContent>
<MudTextField Value="@($"{result.AddressRoad}, {result.HouseNumber}")" Label="Address"
ReadOnly />
<MudTextField Value="@($"{result.AddressRoad}, {result.HouseNumber}")"
Label="@LanguageLocale.general_address_address" ReadOnly />
<MudStack row>
<MudTextField Value="@result.AddressCity" Label="City" ReadOnly />
<MudTextField Value="@result.AddressProvince" Label="Province" ReadOnly />
<MudTextField Value="@result.AddressState" Label="State" ReadOnly />
<MudTextField Value="@result.AddressCity" Label="@LanguageLocale.general_address_city"
ReadOnly />
<MudTextField Value="@result.AddressProvince"
Label="@LanguageLocale.general_address_province" ReadOnly />
<MudTextField Value="@result.AddressState" Label="@LanguageLocale.general_address_state"
ReadOnly />
</MudStack>
<MudStack row>
<MudTextField Value="@result.AddressCountry" Label="Country" ReadOnly />
<MudTextField Value="@result.ZipCode" Label="Zip Code" ReadOnly />
<MudTextField Value="@result.AddressCountry" Label="@LanguageLocale.general_address_country"
ReadOnly />
<MudTextField Value="@result.ZipCode" Label="@LanguageLocale.general_address_zipCode"
ReadOnly />
</MudStack>
</ChildContent>
</MudListItem>
@@ -49,24 +55,46 @@
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Color="Color.Primary" OnClick="btnSelectAddress">Select Address</MudButton>
<MudButton OnClick="Cancel">
@LanguageLocale.general_btnCancel
</MudButton>
<MudButton Color="Color.Primary" OnClick="btnSelectAddress">
@LanguageLocale.control_AddressQueryDialog_btnSelectAddress
</MudButton>
</DialogActions>
</MudDialog>
@code {
// Dialog Instance injected when open by the DialogService.
// This field is null when dialog is not open by the DialogService.
[CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!;
// Reference to the Dialog when open by the ShowAsync Method. (When dialog is used inline).
// This field is null when dialog is not open using the internal methods.
private IDialogReference? _reference;
public string SearchText { get; set; } = "";
//Reference to the MudDialog component. Used to manage the internal dialog when the component is inline.
private MudDialog DialogRef { get; set; } = null!;
private string SearchText { get; set; } = "";
private List<AddressResultDTO> addressResults = [];
private AddressResultDTO? SelectedAddressResult { get; set; }
private MudTextField<string> txtSearch = null!;
private void Cancel() => MudDialog.Cancel();
private void Cancel()
{
if (MudDialog is not null)
{
MudDialog.Cancel();
return;
}
else if (_reference is not null)
{
DialogRef.CloseAsync(DialogResult.Cancel());
return;
}
throw new InvalidOperationException("Unable to cancel (close) the dialog!");
}
private async Task btnSearchAddress()
{
@@ -88,7 +116,7 @@
}
}
private void btnSelectAddress()
private async Task btnSelectAddress()
{
if (SelectedAddressResult is null)
{
@@ -96,8 +124,37 @@
return;
}
//In a real world scenario this bool would probably be a service to delete the item from api/database
Snackbar.Add("Address Selected", Severity.Success);
MudDialog.Close(DialogResult.Ok<AddressResultDTO?>(SelectedAddressResult));
DialogResult dialogResult = DialogResult.Ok<AddressResultDTO?>(SelectedAddressResult);
//Close the dialog when opened by DialogService.
if (MudDialog != null)
{
logger.LogDebug("AddressQueryDialog - Closed MudDialogInstance!");
MudDialog.Close(dialogResult);
return;
}
//Close the dialog when is a Inline dialog.
else if (_reference is not null)
{
logger.LogDebug("AddressQueryDialog - Closed inline dialog instance!");
await DialogRef.CloseAsync(dialogResult);
return;
}
//Throw if the dialog can't be closed (as none of the above is true).
throw new InvalidOperationException("Dialog cannot be closed! No reference to close!");
}
public async Task<IDialogReference> ShowAsync(DialogOptions? options = null)
{
_reference = await DialogRef.ShowAsync(options: options);
return _reference;
}
public async Task CloseAsync()
{
await DialogRef.CloseAsync();
_reference = null;
}
}
@@ -17,14 +17,16 @@
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
<MudStack Row style="@FieldMarginY">
<MudSelect @bind-Value="Model.DocumentType" For="@(() => Model.DocumentType)" Label="@LanguageLocale.dto_GuestDocument_DocumentType"
Required ReadOnly="true">
Required ReadOnly="@ReadOnlyDocId">
@foreach (string docType in dataListService.GetDataListByName(GuestConsts.DataList_DocumentTypes))
{
<MudSelectItem Value="docType">@dataListService.GetLocalizedValue(GuestConsts.DataList_DocumentTypes, docType)</MudSelectItem>
<MudSelectItem Value="docType">
@dataListService.GetLocalizedValue(GuestConsts.DataList_DocumentTypes, docType)
</MudSelectItem>
}
</MudSelect>
<MudTextField @bind-Value="Model.DocumentNum" For="@(() => Model.DocumentNum)" Label="@LanguageLocale.dto_GuestDocument_DocumentNum"
Immediate="true" Required ReadOnly="true" />
Immediate="true" Required ReadOnly="@ReadOnlyDocId" />
</MudStack>
<MudStack Row style="@FieldMarginY">
@@ -64,7 +66,9 @@
<MudSelect @bind-Value="Model.Gender" For="@(() => Model.Gender)" Label="@LanguageLocale.dto_GuestDocument_Gender">
@foreach (string gender in dataListService.GetDataListByName(GuestConsts.DataList_GenderOptions))
{
<MudSelectItem Value="gender">@dataListService.GetLocalizedValue(GuestConsts.DataList_GenderOptions, gender)</MudSelectItem>
<MudSelectItem Value="gender">
@dataListService.GetLocalizedValue(GuestConsts.DataList_GenderOptions, gender)
</MudSelectItem>
}
</MudSelect>
</MudStack>
@@ -92,23 +96,31 @@
<MudText Typo="Typo.subtitle1" Align="Align.Center">@LanguageLocale.control_GuestDocForm_sectionAddress</MudText>
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
<MudTextField @bind-Value="Model.Address" For="@(() => Model.Address)" Immediate="true" Label="@LanguageLocale.dto_GuestDocument_Address" />
@if (!ReadOnly)
{
<MudButton OnClick="BtnOpenAddressSearchDialog" Variant="Variant.Outlined" FullWidth="true" Class="mb-2">
@LanguageLocale.control_GuestDocForm_btnSearchAddress
</MudButton>
}
<MudTextField @bind-Value="Model.Address" For="@(() => Model.Address)"
Label="@LanguageLocale.general_address_address" ReadOnly="@ReadOnlyAddress" />
<MudStack Row style="@FieldMarginY">
<MudTextField @bind-Value="Model.AddressCity" For="@(() => Model.AddressCity)"
Label="@LanguageLocale.dto_GuestDocument_AddressCity" Immediate="true" />
Label="@LanguageLocale.general_address_city" ReadOnly="@ReadOnlyAddress" />
<MudTextField @bind-Value="Model.AddressProvince" For="@(() => Model.AddressProvince)"
Label="@LanguageLocale.dto_GuestDocument_AddressProvince" Immediate="true" />
Label="@LanguageLocale.general_address_province" ReadOnly="@ReadOnlyAddress" />
<MudTextField @bind-Value="Model.AddressState" For="@(() => Model.AddressState)"
Label="@LanguageLocale.dto_GuestDocument_AddressState" Immediate="true" />
Label="@LanguageLocale.general_address_state" ReadOnly="@ReadOnlyAddress" />
</MudStack>
<MudStack Row style="@FieldMarginY">
<MudAutocomplete T="string" @bind-Value="Model.AddressCountry" For="@(() => Model.AddressCountry)"
Label="@LanguageLocale.dto_GuestDocument_AddressCountry"
Label="@LanguageLocale.general_address_country" ReadOnly="@ReadOnlyAddress"
SearchFunc="@SearchCountryCodes" ToStringFunc="@(e=> string.IsNullOrEmpty(e) ? "" : @dataListService.GetLocalizedValue(GuestConsts.DataList_CountryCodes, e))"
SelectValueOnTab="true" AdornmentIcon="@Icons.Material.Filled.Search" />
<MudTextField @bind-Value="Model.ZipCode" For="@(() => Model.ZipCode)" Immediate="true"
Label="@LanguageLocale.dto_GuestDocument_ZipCode" />
<MudTextField @bind-Value="Model.ZipCode" For="@(() => Model.ZipCode)"
Label="@LanguageLocale.general_address_zipCode" ReadOnly="@ReadOnlyAddress" />
</MudStack>
</MudPaper>
</MudItem>
@@ -116,6 +128,8 @@
<MudText Class="mt-4">@CreateTimeString</MudText>
</MudForm>
<AddressQueryDialog @ref="@AddressQueryDialog" />
@code {
[Parameter]
@@ -124,9 +138,21 @@
[Parameter]
public bool ReadOnly { get; set; } = false;
[Parameter]
public bool ReadOnlyDocId { get; set; } = true;
private MudForm _form = null!;
AddressQueryDialog AddressQueryDialog { get; set; } = null!;
DialogOptions AddressQueryDialogOptions = new()
{
MaxWidth = MaxWidth.Large,
FullWidth = true,
};
private bool ReadOnlyAddress { get; set; } = true;
private const string FieldMarginY = "margin-block: 0.5em";
private Dictionary<string, string>? countryDict = null;
private bool isSuportNumberRequired { get => Model?.Nationality == GuestConsts.CountryCode_ESP; }
@@ -178,4 +204,39 @@
.Select(x => x.Key);
}
#region Event Handlers
private async Task BtnOpenAddressSearchDialog()
{
var reference = await AddressQueryDialog.ShowAsync(options: AddressQueryDialogOptions);
DialogResult? result = await reference.Result;
if (result is null || result.Canceled)
{
return;
}
AddressResultDTO? resultData = await reference.GetReturnValueAsync<AddressResultDTO>();
if (resultData is null)
{
return;
}
//Update Address info.
Model.Address = $"{resultData.AddressRoad}, {resultData.HouseNumber}";
Model.AddressCity = resultData.AddressCity;
Model.AddressProvince = resultData.AddressProvince;
Model.AddressState = resultData.AddressState;
Model.ZipCode = resultData.ZipCode;
//Set country by address code.
Model.AddressCountry = resultData.AddressCountryCode;
//Address is editable after searching (if the form is editable).
ReadOnlyAddress = ReadOnly;
}
#endregion
}