SHA256
Compare commits
2
Commits
3fe558c231
...
8232e7d7c9
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
8232e7d7c9 | ||
|
|
5c7fed2677 |
@@ -0,0 +1,160 @@
|
|||||||
|
@using Somnia.GuestLog.Models.DTOs;
|
||||||
|
@using Somnia.GuestLog.Services.AddressQuery;
|
||||||
|
|
||||||
|
@inject ILogger<AddressQueryDialog> logger;
|
||||||
|
@inject IAddressQueryFactory addressQueryFactory;
|
||||||
|
@inject ISnackbar Snackbar
|
||||||
|
|
||||||
|
<MudDialog @ref="@DialogRef">
|
||||||
|
<TitleContent>
|
||||||
|
<MudText Typo="Typo.h6">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.NotListedLocation" Class="mr-3 mb-n1" />
|
||||||
|
@LanguageLocale.control_AddressQueryDialog_dialogTitle
|
||||||
|
</MudText>
|
||||||
|
</TitleContent>
|
||||||
|
<DialogContent>
|
||||||
|
<MudStack row>
|
||||||
|
<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">@LanguageLocale.general_noResults</MudText>
|
||||||
|
}
|
||||||
|
|
||||||
|
<MudList T="AddressResultDTO" @bind-SelectedValue="SelectedAddressResult"
|
||||||
|
SelectionMode="SelectionMode.SingleSelection" Color="Color.Info">
|
||||||
|
@foreach (AddressResultDTO result in addressResults)
|
||||||
|
{
|
||||||
|
<MudListItem Value="result">
|
||||||
|
<ChildContent>
|
||||||
|
<MudTextField Value="@($"{result.AddressRoad}, {result.HouseNumber}")"
|
||||||
|
Label="@LanguageLocale.general_address_address" ReadOnly />
|
||||||
|
<MudStack row>
|
||||||
|
<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="@LanguageLocale.general_address_country"
|
||||||
|
ReadOnly />
|
||||||
|
<MudTextField Value="@result.ZipCode" Label="@LanguageLocale.general_address_zipCode"
|
||||||
|
ReadOnly />
|
||||||
|
</MudStack>
|
||||||
|
</ChildContent>
|
||||||
|
</MudListItem>
|
||||||
|
}
|
||||||
|
</MudList>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<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;
|
||||||
|
|
||||||
|
//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 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()
|
||||||
|
{
|
||||||
|
if (SearchText.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var queryService = addressQueryFactory.GetService();
|
||||||
|
|
||||||
|
addressResults = await queryService.SearchAddressAsync(SearchText);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogError(ex, "SearchAddress returned an error!");
|
||||||
|
Snackbar.Add($"Error searching address: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task btnSelectAddress()
|
||||||
|
{
|
||||||
|
if (SelectedAddressResult is null)
|
||||||
|
{
|
||||||
|
Snackbar.Add("Select an address", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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" />
|
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
|
||||||
<MudStack Row style="@FieldMarginY">
|
<MudStack Row style="@FieldMarginY">
|
||||||
<MudSelect @bind-Value="Model.DocumentType" For="@(() => Model.DocumentType)" Label="@LanguageLocale.dto_GuestDocument_DocumentType"
|
<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))
|
@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>
|
</MudSelect>
|
||||||
<MudTextField @bind-Value="Model.DocumentNum" For="@(() => Model.DocumentNum)" Label="@LanguageLocale.dto_GuestDocument_DocumentNum"
|
<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>
|
||||||
|
|
||||||
<MudStack Row style="@FieldMarginY">
|
<MudStack Row style="@FieldMarginY">
|
||||||
@@ -64,7 +66,9 @@
|
|||||||
<MudSelect @bind-Value="Model.Gender" For="@(() => Model.Gender)" Label="@LanguageLocale.dto_GuestDocument_Gender">
|
<MudSelect @bind-Value="Model.Gender" For="@(() => Model.Gender)" Label="@LanguageLocale.dto_GuestDocument_Gender">
|
||||||
@foreach (string gender in dataListService.GetDataListByName(GuestConsts.DataList_GenderOptions))
|
@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>
|
</MudSelect>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
@@ -92,23 +96,31 @@
|
|||||||
<MudText Typo="Typo.subtitle1" Align="Align.Center">@LanguageLocale.control_GuestDocForm_sectionAddress</MudText>
|
<MudText Typo="Typo.subtitle1" Align="Align.Center">@LanguageLocale.control_GuestDocForm_sectionAddress</MudText>
|
||||||
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
|
<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">
|
<MudStack Row style="@FieldMarginY">
|
||||||
<MudTextField @bind-Value="Model.AddressCity" For="@(() => Model.AddressCity)"
|
<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)"
|
<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)"
|
<MudTextField @bind-Value="Model.AddressState" For="@(() => Model.AddressState)"
|
||||||
Label="@LanguageLocale.dto_GuestDocument_AddressState" Immediate="true" />
|
Label="@LanguageLocale.general_address_state" ReadOnly="@ReadOnlyAddress" />
|
||||||
</MudStack>
|
</MudStack>
|
||||||
<MudStack Row style="@FieldMarginY">
|
<MudStack Row style="@FieldMarginY">
|
||||||
<MudAutocomplete T="string" @bind-Value="Model.AddressCountry" For="@(() => Model.AddressCountry)"
|
<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))"
|
SearchFunc="@SearchCountryCodes" ToStringFunc="@(e=> string.IsNullOrEmpty(e) ? "" : @dataListService.GetLocalizedValue(GuestConsts.DataList_CountryCodes, e))"
|
||||||
SelectValueOnTab="true" AdornmentIcon="@Icons.Material.Filled.Search" />
|
SelectValueOnTab="true" AdornmentIcon="@Icons.Material.Filled.Search" />
|
||||||
|
|
||||||
<MudTextField @bind-Value="Model.ZipCode" For="@(() => Model.ZipCode)" Immediate="true"
|
<MudTextField @bind-Value="Model.ZipCode" For="@(() => Model.ZipCode)"
|
||||||
Label="@LanguageLocale.dto_GuestDocument_ZipCode" />
|
Label="@LanguageLocale.general_address_zipCode" ReadOnly="@ReadOnlyAddress" />
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
@@ -116,6 +128,8 @@
|
|||||||
<MudText Class="mt-4">@CreateTimeString</MudText>
|
<MudText Class="mt-4">@CreateTimeString</MudText>
|
||||||
</MudForm>
|
</MudForm>
|
||||||
|
|
||||||
|
<AddressQueryDialog @ref="@AddressQueryDialog" />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
@@ -124,9 +138,21 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ReadOnly { get; set; } = false;
|
public bool ReadOnly { get; set; } = false;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool ReadOnlyDocId { get; set; } = true;
|
||||||
|
|
||||||
|
|
||||||
private MudForm _form = null!;
|
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 const string FieldMarginY = "margin-block: 0.5em";
|
||||||
|
|
||||||
private Dictionary<string, string>? countryDict = null;
|
private Dictionary<string, string>? countryDict = null;
|
||||||
|
|
||||||
private bool isSuportNumberRequired { get => Model?.Nationality == GuestConsts.CountryCode_ESP; }
|
private bool isSuportNumberRequired { get => Model?.Nationality == GuestConsts.CountryCode_ESP; }
|
||||||
@@ -178,4 +204,39 @@
|
|||||||
.Select(x => x.Key);
|
.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
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,16 +6,20 @@
|
|||||||
@inject ILogger<AddressQuery> logger;
|
@inject ILogger<AddressQuery> logger;
|
||||||
@inject IAddressQueryFactory addressQueryFactory;
|
@inject IAddressQueryFactory addressQueryFactory;
|
||||||
@inject ISnackbar Snackbar
|
@inject ISnackbar Snackbar
|
||||||
|
@inject IDialogService DialogService
|
||||||
|
|
||||||
<PageTitle>DEBUG - Address Query</PageTitle>
|
<PageTitle>DEBUG - Address Query</PageTitle>
|
||||||
|
|
||||||
<MudText Typo="Typo.h3" GutterBottom="true">Address Search</MudText>
|
<MudText Typo="Typo.h3" GutterBottom="true" Class="mt-2">Address Search</MudText>
|
||||||
|
|
||||||
|
<MudPaper Class="ma-2 pa-4">
|
||||||
|
<MudStack Row>
|
||||||
<MudTextField @ref="txtSearch" @bind-Value="SearchText" Label="Search address" Required />
|
<MudTextField @ref="txtSearch" @bind-Value="SearchText" Label="Search address" Required />
|
||||||
|
<MudButton Color="Color.Primary" Variant="Variant.Filled" @onclick="btnSearchAddress" Class="mt-2">Search
|
||||||
|
</MudButton>
|
||||||
|
</MudStack>
|
||||||
|
|
||||||
<MudButton Color="Color.Primary" Variant="Variant.Filled" @onclick="btnSearchAddress">Search</MudButton>
|
<MudPaper class="mt-2 pa-4">
|
||||||
|
|
||||||
<MudPaper>
|
|
||||||
@if (addressResults.Count == 0)
|
@if (addressResults.Count == 0)
|
||||||
{
|
{
|
||||||
<MudText Typo="Typo.body1">No results!</MudText>
|
<MudText Typo="Typo.body1">No results!</MudText>
|
||||||
@@ -34,6 +38,30 @@
|
|||||||
</MudItem>
|
</MudItem>
|
||||||
}
|
}
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
<MudDivider DividerType="DividerType.FullWidth" />
|
||||||
|
|
||||||
|
<MudPaper Class="ma-2 pa-4">
|
||||||
|
<MudButton OnClick="btnOpenSearchDialog" Color="Color.Primary" Variant="Variant.Filled" FullWidth>
|
||||||
|
Open Search Dialog
|
||||||
|
</MudButton>
|
||||||
|
|
||||||
|
@if (dialogSelectedAddress is not null)
|
||||||
|
{
|
||||||
|
<MudPaper class="mt-2 pa-4">
|
||||||
|
<MudText>Selected Address: </MudText>
|
||||||
|
<MudStack>
|
||||||
|
<MudText>Address: @dialogSelectedAddress.AddressRoad , @dialogSelectedAddress.HouseNumber</MudText>
|
||||||
|
<MudText>City: @dialogSelectedAddress.AddressCity</MudText>
|
||||||
|
<MudText>Province: @dialogSelectedAddress.AddressProvince</MudText>
|
||||||
|
<MudText>State: @dialogSelectedAddress.AddressState</MudText>
|
||||||
|
<MudText>Country: @dialogSelectedAddress.AddressCountry</MudText>
|
||||||
|
<MudText>ZipCode: @dialogSelectedAddress.ZipCode</MudText>
|
||||||
|
</MudStack>
|
||||||
|
</MudPaper>
|
||||||
|
}
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
@@ -42,6 +70,8 @@
|
|||||||
|
|
||||||
private MudTextField<string> txtSearch = null!;
|
private MudTextField<string> txtSearch = null!;
|
||||||
|
|
||||||
|
private AddressResultDTO? dialogSelectedAddress = null;
|
||||||
|
|
||||||
private async Task btnSearchAddress()
|
private async Task btnSearchAddress()
|
||||||
{
|
{
|
||||||
if (SearchText.Length == 0)
|
if (SearchText.Length == 0)
|
||||||
@@ -62,4 +92,23 @@
|
|||||||
Snackbar.Add($"Error searching address: {ex.Message}", Severity.Error);
|
Snackbar.Add($"Error searching address: {ex.Message}", Severity.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task btnOpenSearchDialog()
|
||||||
|
{
|
||||||
|
DialogOptions options = new()
|
||||||
|
{
|
||||||
|
MaxWidth = MaxWidth.Large,
|
||||||
|
FullWidth= true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialog = await DialogService.ShowAsync<AddressQueryDialog>("Search Address", options);
|
||||||
|
DialogResult? result = await dialog.Result;
|
||||||
|
|
||||||
|
if (result is not null && !result.Canceled)
|
||||||
|
{
|
||||||
|
AddressResultDTO? resultData = await dialog.GetReturnValueAsync<AddressResultDTO>();
|
||||||
|
|
||||||
|
dialogSelectedAddress = resultData;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public class AddressQueryConfig
|
|||||||
public string? ServiceURL { get; set; }
|
public string? ServiceURL { get; set; }
|
||||||
public string? ApiKey { get; set; }
|
public string? ApiKey { get; set; }
|
||||||
public string? UserAgent { get; set; }
|
public string? UserAgent { get; set; }
|
||||||
|
public string? ResultLang { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public enum AddressQueryProviderEnum
|
public enum AddressQueryProviderEnum
|
||||||
|
|||||||
@@ -9,4 +9,9 @@ public class AddressResultDTO
|
|||||||
public string? AddressState { get; set; }
|
public string? AddressState { get; set; }
|
||||||
public string? AddressCountry { get; set; }
|
public string? AddressCountry { get; set; }
|
||||||
public string? ZipCode { get; set; }
|
public string? ZipCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CountryCode in ISO3166-1:alpha3
|
||||||
|
/// </summary>
|
||||||
|
public string? AddressCountryCode { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,12 +134,6 @@
|
|||||||
<data name="dto.GuestDocument.Gender" xml:space="preserve"><value>Gender</value></data>
|
<data name="dto.GuestDocument.Gender" xml:space="preserve"><value>Gender</value></data>
|
||||||
<data name="dto.GuestDocument.PhoneNumber" xml:space="preserve"><value>Phone Number</value></data>
|
<data name="dto.GuestDocument.PhoneNumber" xml:space="preserve"><value>Phone Number</value></data>
|
||||||
<data name="dto.GuestDocument.EmailAddress" xml:space="preserve"><value>Email Address</value></data>
|
<data name="dto.GuestDocument.EmailAddress" xml:space="preserve"><value>Email Address</value></data>
|
||||||
<data name="dto.GuestDocument.Address" xml:space="preserve"><value>Address</value></data>
|
|
||||||
<data name="dto.GuestDocument.AddressCity" xml:space="preserve"><value>City</value></data>
|
|
||||||
<data name="dto.GuestDocument.AddressProvince" xml:space="preserve"><value>County</value></data>
|
|
||||||
<data name="dto.GuestDocument.AddressState" xml:space="preserve"><value>State</value></data>
|
|
||||||
<data name="dto.GuestDocument.AddressCountry" xml:space="preserve"><value>Country</value></data>
|
|
||||||
<data name="dto.GuestDocument.ZipCode" xml:space="preserve"><value>Zip Code</value></data>
|
|
||||||
<data name="dto.GuestDocument.CreateTime" xml:space="preserve"><value>Creation Time</value></data>
|
<data name="dto.GuestDocument.CreateTime" xml:space="preserve"><value>Creation Time</value></data>
|
||||||
<data name="dto.GuestDocument.UpdateTime" xml:space="preserve"><value>Update Time</value></data>
|
<data name="dto.GuestDocument.UpdateTime" xml:space="preserve"><value>Update Time</value></data>
|
||||||
|
|
||||||
@@ -156,8 +150,16 @@
|
|||||||
<data name="general.btnSearch" xml:space="preserve"><value>Search</value></data>
|
<data name="general.btnSearch" xml:space="preserve"><value>Search</value></data>
|
||||||
<data name="general.btnSave" xml:space="preserve"><value>Save</value></data>
|
<data name="general.btnSave" xml:space="preserve"><value>Save</value></data>
|
||||||
<data name="general.btnCancel" xml:space="preserve"><value>Cancel</value></data>
|
<data name="general.btnCancel" xml:space="preserve"><value>Cancel</value></data>
|
||||||
|
<data name="general.noResults" xml:space="preserve"><value>No Results!</value></data>
|
||||||
<data name="general.wildcardHelperText" xml:space="preserve"><value>Use '%' as wildcard</value></data>
|
<data name="general.wildcardHelperText" xml:space="preserve"><value>Use '%' as wildcard</value></data>
|
||||||
|
|
||||||
|
<data name="general.address.address" xml:space="preserve"><value>Address</value></data>
|
||||||
|
<data name="general.address.city" xml:space="preserve"><value>City</value></data>
|
||||||
|
<data name="general.address.province" xml:space="preserve"><value>County</value></data>
|
||||||
|
<data name="general.address.state" xml:space="preserve"><value>State</value></data>
|
||||||
|
<data name="general.address.country" xml:space="preserve"><value>Country</value></data>
|
||||||
|
<data name="general.address.zipCode" xml:space="preserve"><value>Zip Code</value></data>
|
||||||
|
|
||||||
<data name="page.GuestDocList.pageTitle" xml:space="preserve"><value>Guest Documents</value></data>
|
<data name="page.GuestDocList.pageTitle" xml:space="preserve"><value>Guest Documents</value></data>
|
||||||
<data name="page.GuestDocList.documentList" xml:space="preserve"><value>Document List</value></data>
|
<data name="page.GuestDocList.documentList" xml:space="preserve"><value>Document List</value></data>
|
||||||
<data name="page.GuestDocList.btnNewGuest" xml:space="preserve"><value>New Guest</value></data>
|
<data name="page.GuestDocList.btnNewGuest" xml:space="preserve"><value>New Guest</value></data>
|
||||||
@@ -170,5 +172,11 @@
|
|||||||
<data name="control.GuestDocForm.sectionGuest" xml:space="preserve"><value>Guest Details</value></data>
|
<data name="control.GuestDocForm.sectionGuest" xml:space="preserve"><value>Guest Details</value></data>
|
||||||
<data name="control.GuestDocForm.sectionContact" xml:space="preserve"><value>Contact Details</value></data>
|
<data name="control.GuestDocForm.sectionContact" xml:space="preserve"><value>Contact Details</value></data>
|
||||||
<data name="control.GuestDocForm.sectionAddress" xml:space="preserve"><value>Guest Address</value></data>
|
<data name="control.GuestDocForm.sectionAddress" xml:space="preserve"><value>Guest Address</value></data>
|
||||||
|
<data name="control.GuestDocForm.btnSearchAddress" xml:space="preserve"><value>Search Address</value></data>
|
||||||
|
|
||||||
|
<data name="control.AddressQueryDialog.dialogTitle" xml:space="preserve"><value>Search Address</value></data>
|
||||||
|
<data name="control.AddressQueryDialog.searchText" xml:space="preserve"><value>Search Address</value></data>
|
||||||
|
<data name="control.AddressQueryDialog.btnSearch" xml:space="preserve"><value>Search Address</value></data>
|
||||||
|
<data name="control.AddressQueryDialog.btnSelectAddress" xml:space="preserve"><value>Use Address</value></data>
|
||||||
|
|
||||||
</root>
|
</root>
|
||||||
@@ -2,6 +2,7 @@ using Microsoft.AspNetCore.WebUtilities;
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Somnia.GuestLog.Models.Configuration;
|
using Somnia.GuestLog.Models.Configuration;
|
||||||
using Somnia.GuestLog.Models.DTOs;
|
using Somnia.GuestLog.Models.DTOs;
|
||||||
|
using Somnia.GuestLog.Utils;
|
||||||
|
|
||||||
namespace Somnia.GuestLog.Services.AddressQuery;
|
namespace Somnia.GuestLog.Services.AddressQuery;
|
||||||
|
|
||||||
@@ -36,6 +37,8 @@ public class NominatimAddressQueryService(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string? alpha3CountryCode = CountryCodesUtils.Alpha2ToAlpha3(result.Address.Country_code);
|
||||||
|
|
||||||
rsList.Add(new()
|
rsList.Add(new()
|
||||||
{
|
{
|
||||||
HouseNumber = result.Address.House_number,
|
HouseNumber = result.Address.House_number,
|
||||||
@@ -44,7 +47,8 @@ public class NominatimAddressQueryService(
|
|||||||
AddressProvince = result.Address.Province,
|
AddressProvince = result.Address.Province,
|
||||||
AddressState = result.Address.State,
|
AddressState = result.Address.State,
|
||||||
AddressCountry = result.Address.Country,
|
AddressCountry = result.Address.Country,
|
||||||
ZipCode = result.Address.Postcode
|
ZipCode = result.Address.Postcode,
|
||||||
|
AddressCountryCode = alpha3CountryCode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +70,10 @@ public class NominatimAddressQueryService(
|
|||||||
|
|
||||||
client.BaseAddress = baseAddr;
|
client.BaseAddress = baseAddr;
|
||||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(config.UserAgent ?? defaultUserAgent);
|
client.DefaultRequestHeaders.UserAgent.ParseAdd(config.UserAgent ?? defaultUserAgent);
|
||||||
client.DefaultRequestHeaders.AcceptLanguage.ParseAdd("es");
|
if (config.ResultLang is not null)
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.AcceptLanguage.ParseAdd(config.ResultLang);
|
||||||
|
}
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
@@ -92,7 +99,8 @@ public class NominatimAddressQueryService(
|
|||||||
string? Province = null,
|
string? Province = null,
|
||||||
string? State = null,
|
string? State = null,
|
||||||
string? Country = null,
|
string? Country = null,
|
||||||
string? Postcode = null
|
string? Postcode = null,
|
||||||
|
string? Country_code = null
|
||||||
);
|
);
|
||||||
|
|
||||||
private record class ApiResult(
|
private record class ApiResult(
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
namespace Somnia.GuestLog.Utils;
|
||||||
|
|
||||||
|
public static class CountryCodesUtils
|
||||||
|
{
|
||||||
|
// Returns null when input is invalid/unknown.
|
||||||
|
public static string? Alpha2ToAlpha3(string? alpha2)
|
||||||
|
{
|
||||||
|
if (alpha2 is null) return null;
|
||||||
|
|
||||||
|
// Common normalization: trim + uppercase.
|
||||||
|
// Avoids issues with "us", " US ", etc.
|
||||||
|
var key = alpha2.Trim().ToUpperInvariant();
|
||||||
|
|
||||||
|
if (key.Length != 2) return null;
|
||||||
|
|
||||||
|
return Alpha2ToAlpha3Dict.TryGetValue(key, out var alpha3) ? alpha3 : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throwing for invalid/unknown codes
|
||||||
|
public static string Alpha2ToAlpha3OrThrow(string alpha2)
|
||||||
|
{
|
||||||
|
var result = Alpha2ToAlpha3(alpha2)
|
||||||
|
?? throw new ArgumentException("Unknown or invalid ISO 3166-1 alpha2 code.", nameof(alpha2));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build-time constant lookup.
|
||||||
|
// Keys are ISO 3166-1 alpha-2 codes (uppercase).
|
||||||
|
private static readonly Dictionary<string, string> Alpha2ToAlpha3Dict =
|
||||||
|
new(StringComparer.Ordinal)
|
||||||
|
{
|
||||||
|
["AF"] = "AFG",
|
||||||
|
["AX"] = "ALA",
|
||||||
|
["AL"] = "ALB",
|
||||||
|
["DZ"] = "DZA",
|
||||||
|
["AS"] = "ASM",
|
||||||
|
["AD"] = "AND",
|
||||||
|
["AO"] = "AGO",
|
||||||
|
["AI"] = "AIA",
|
||||||
|
["AQ"] = "ATA",
|
||||||
|
["AG"] = "ATG",
|
||||||
|
["AR"] = "ARG",
|
||||||
|
["AM"] = "ARM",
|
||||||
|
["AW"] = "ABW",
|
||||||
|
["AU"] = "AUS",
|
||||||
|
["AT"] = "AUT",
|
||||||
|
["AZ"] = "AZE",
|
||||||
|
["BS"] = "BHS",
|
||||||
|
["BH"] = "BHR",
|
||||||
|
["BD"] = "BGD",
|
||||||
|
["BB"] = "BRB",
|
||||||
|
["BY"] = "BLR",
|
||||||
|
["BE"] = "BEL",
|
||||||
|
["BZ"] = "BLZ",
|
||||||
|
["BJ"] = "BEN",
|
||||||
|
["BM"] = "BMU",
|
||||||
|
["BT"] = "BTN",
|
||||||
|
["BO"] = "BOL",
|
||||||
|
["BQ"] = "BES",
|
||||||
|
["BA"] = "BIH",
|
||||||
|
["BW"] = "BWA",
|
||||||
|
["BV"] = "BVT",
|
||||||
|
["BR"] = "BRA",
|
||||||
|
["IO"] = "IOT",
|
||||||
|
["BN"] = "BRN",
|
||||||
|
["BG"] = "BGR",
|
||||||
|
["BF"] = "BFA",
|
||||||
|
["BI"] = "BDI",
|
||||||
|
["CV"] = "CPV",
|
||||||
|
["KH"] = "KHM",
|
||||||
|
["CM"] = "CMR",
|
||||||
|
["CA"] = "CAN",
|
||||||
|
["KY"] = "CYM",
|
||||||
|
["CF"] = "CAF",
|
||||||
|
["TD"] = "TCD",
|
||||||
|
["CL"] = "CHL",
|
||||||
|
["CN"] = "CHN",
|
||||||
|
["CX"] = "CXR",
|
||||||
|
["CC"] = "CCK",
|
||||||
|
["CO"] = "COL",
|
||||||
|
["KM"] = "COM",
|
||||||
|
["CG"] = "COG",
|
||||||
|
["CD"] = "COD",
|
||||||
|
["CK"] = "COK",
|
||||||
|
["CR"] = "CRI",
|
||||||
|
["CI"] = "CIV",
|
||||||
|
["HR"] = "HRV",
|
||||||
|
["CU"] = "CUB",
|
||||||
|
["CW"] = "CUW",
|
||||||
|
["CY"] = "CYP",
|
||||||
|
["CZ"] = "CZE",
|
||||||
|
["DK"] = "DNK",
|
||||||
|
["DJ"] = "DJI",
|
||||||
|
["DM"] = "DMA",
|
||||||
|
["DO"] = "DOM",
|
||||||
|
["EC"] = "ECU",
|
||||||
|
["EG"] = "EGY",
|
||||||
|
["SV"] = "SLV",
|
||||||
|
["GQ"] = "GNQ",
|
||||||
|
["ER"] = "ERI",
|
||||||
|
["EE"] = "EST",
|
||||||
|
["SZ"] = "SWZ",
|
||||||
|
["ET"] = "ETH",
|
||||||
|
["FK"] = "FLK",
|
||||||
|
["FO"] = "FRO",
|
||||||
|
["FJ"] = "FJI",
|
||||||
|
["FI"] = "FIN",
|
||||||
|
["FR"] = "FRA",
|
||||||
|
["GF"] = "GUF",
|
||||||
|
["PF"] = "PYF",
|
||||||
|
["TF"] = "ATF",
|
||||||
|
["GA"] = "GAB",
|
||||||
|
["GM"] = "GMB",
|
||||||
|
["GE"] = "GEO",
|
||||||
|
["DE"] = "DEU",
|
||||||
|
["GH"] = "GHA",
|
||||||
|
["GI"] = "GIB",
|
||||||
|
["GR"] = "GRC",
|
||||||
|
["GL"] = "GRL",
|
||||||
|
["GD"] = "GRD",
|
||||||
|
["GP"] = "GLP",
|
||||||
|
["GU"] = "GUM",
|
||||||
|
["GT"] = "GTM",
|
||||||
|
["GG"] = "GGY",
|
||||||
|
["GN"] = "GIN",
|
||||||
|
["GW"] = "GNB",
|
||||||
|
["GY"] = "GUY",
|
||||||
|
["HT"] = "HTI",
|
||||||
|
["HM"] = "HMD",
|
||||||
|
["VA"] = "VAT",
|
||||||
|
["HN"] = "HND",
|
||||||
|
["HK"] = "HKG",
|
||||||
|
["HU"] = "HUN",
|
||||||
|
["IS"] = "ISL",
|
||||||
|
["IN"] = "IND",
|
||||||
|
["ID"] = "IDN",
|
||||||
|
["IR"] = "IRN",
|
||||||
|
["IQ"] = "IRQ",
|
||||||
|
["IE"] = "IRL",
|
||||||
|
["IM"] = "IMN",
|
||||||
|
["IL"] = "ISR",
|
||||||
|
["IT"] = "ITA",
|
||||||
|
["JM"] = "JAM",
|
||||||
|
["JP"] = "JPN",
|
||||||
|
["JE"] = "JEY",
|
||||||
|
["JO"] = "JOR",
|
||||||
|
["KZ"] = "KAZ",
|
||||||
|
["KE"] = "KEN",
|
||||||
|
["KI"] = "KIR",
|
||||||
|
["KP"] = "PRK",
|
||||||
|
["KR"] = "KOR",
|
||||||
|
["KW"] = "KWT",
|
||||||
|
["KG"] = "KGZ",
|
||||||
|
["LA"] = "LAO",
|
||||||
|
["LV"] = "LVA",
|
||||||
|
["LB"] = "LBN",
|
||||||
|
["LS"] = "LSO",
|
||||||
|
["LR"] = "LBR",
|
||||||
|
["LY"] = "LBY",
|
||||||
|
["LI"] = "LIE",
|
||||||
|
["LT"] = "LTU",
|
||||||
|
["LU"] = "LUX",
|
||||||
|
["MO"] = "MAC",
|
||||||
|
["MG"] = "MDG",
|
||||||
|
["MW"] = "MWI",
|
||||||
|
["MY"] = "MYS",
|
||||||
|
["MV"] = "MDV",
|
||||||
|
["ML"] = "MLI",
|
||||||
|
["MT"] = "MLT",
|
||||||
|
["MH"] = "MHL",
|
||||||
|
["MQ"] = "MTQ",
|
||||||
|
["MR"] = "MRT",
|
||||||
|
["MU"] = "MUS",
|
||||||
|
["YT"] = "MYT",
|
||||||
|
["MX"] = "MEX",
|
||||||
|
["FM"] = "FSM",
|
||||||
|
["MD"] = "MDA",
|
||||||
|
["MC"] = "MCO",
|
||||||
|
["MN"] = "MNG",
|
||||||
|
["ME"] = "MNE",
|
||||||
|
["MS"] = "MSR",
|
||||||
|
["MA"] = "MAR",
|
||||||
|
["MZ"] = "MOZ",
|
||||||
|
["MM"] = "MMR",
|
||||||
|
["NA"] = "NAM",
|
||||||
|
["NR"] = "NRU",
|
||||||
|
["NP"] = "NPL",
|
||||||
|
["NL"] = "NLD",
|
||||||
|
["NC"] = "NCL",
|
||||||
|
["NZ"] = "NZL",
|
||||||
|
["NI"] = "NIC",
|
||||||
|
["NE"] = "NER",
|
||||||
|
["NG"] = "NGA",
|
||||||
|
["NU"] = "NIU",
|
||||||
|
["NF"] = "NFK",
|
||||||
|
["MK"] = "MKD",
|
||||||
|
["MP"] = "MNP",
|
||||||
|
["NO"] = "NOR",
|
||||||
|
["OM"] = "OMN",
|
||||||
|
["PK"] = "PAK",
|
||||||
|
["PW"] = "PLW",
|
||||||
|
["PS"] = "PSE",
|
||||||
|
["PA"] = "PAN",
|
||||||
|
["PG"] = "PNG",
|
||||||
|
["PY"] = "PRY",
|
||||||
|
["PE"] = "PER",
|
||||||
|
["PH"] = "PHL",
|
||||||
|
["PN"] = "PCN",
|
||||||
|
["PL"] = "POL",
|
||||||
|
["PT"] = "PRT",
|
||||||
|
["PR"] = "PRI",
|
||||||
|
["QA"] = "QAT",
|
||||||
|
["RE"] = "REU",
|
||||||
|
["RO"] = "ROU",
|
||||||
|
["RU"] = "RUS",
|
||||||
|
["RW"] = "RWA",
|
||||||
|
["BL"] = "BLM",
|
||||||
|
["SH"] = "SHN",
|
||||||
|
["KN"] = "KNA",
|
||||||
|
["LC"] = "LCA",
|
||||||
|
["MF"] = "MAF",
|
||||||
|
["PM"] = "SPM",
|
||||||
|
["VC"] = "VCT",
|
||||||
|
["WS"] = "WSM",
|
||||||
|
["SM"] = "SMR",
|
||||||
|
["ST"] = "STP",
|
||||||
|
["SA"] = "SAU",
|
||||||
|
["SN"] = "SEN",
|
||||||
|
["RS"] = "SRB",
|
||||||
|
["SC"] = "SYC",
|
||||||
|
["SL"] = "SLE",
|
||||||
|
["SG"] = "SGP",
|
||||||
|
["SX"] = "SXM",
|
||||||
|
["SK"] = "SVK",
|
||||||
|
["SI"] = "SVN",
|
||||||
|
["SB"] = "SLB",
|
||||||
|
["SO"] = "SOM",
|
||||||
|
["ZA"] = "ZAF",
|
||||||
|
["GS"] = "SGS",
|
||||||
|
["SS"] = "SSD",
|
||||||
|
["ES"] = "ESP",
|
||||||
|
["LK"] = "LKA",
|
||||||
|
["SD"] = "SDN",
|
||||||
|
["SR"] = "SUR",
|
||||||
|
["SJ"] = "SJM",
|
||||||
|
["SE"] = "SWE",
|
||||||
|
["CH"] = "CHE",
|
||||||
|
["SY"] = "SYR",
|
||||||
|
["TW"] = "TWN",
|
||||||
|
["TJ"] = "TJK",
|
||||||
|
["TZ"] = "TZA",
|
||||||
|
["TH"] = "THA",
|
||||||
|
["TL"] = "TLS",
|
||||||
|
["TG"] = "TGO",
|
||||||
|
["TK"] = "TKL",
|
||||||
|
["TO"] = "TON",
|
||||||
|
["TT"] = "TTO",
|
||||||
|
["TN"] = "TUN",
|
||||||
|
["TR"] = "TUR",
|
||||||
|
["TM"] = "TKM",
|
||||||
|
["TC"] = "TCA",
|
||||||
|
["TV"] = "TUV",
|
||||||
|
["UG"] = "UGA",
|
||||||
|
["UA"] = "UKR",
|
||||||
|
["AE"] = "ARE",
|
||||||
|
["GB"] = "GBR",
|
||||||
|
["US"] = "USA",
|
||||||
|
["UM"] = "UMI",
|
||||||
|
["UY"] = "URY",
|
||||||
|
["UZ"] = "UZB",
|
||||||
|
["VU"] = "VUT",
|
||||||
|
["VE"] = "VEN",
|
||||||
|
["VN"] = "VNM",
|
||||||
|
["VG"] = "VGB",
|
||||||
|
["VI"] = "VIR",
|
||||||
|
["WF"] = "WLF",
|
||||||
|
["EH"] = "ESH",
|
||||||
|
["YE"] = "YEM",
|
||||||
|
["ZM"] = "ZMB",
|
||||||
|
["ZW"] = "ZWE",
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
"Provider": "Nominatim",
|
"Provider": "Nominatim",
|
||||||
"ServiceURL": "https://nominatim.openstreetmap.org/",
|
"ServiceURL": "https://nominatim.openstreetmap.org/",
|
||||||
"ApiKey": "",
|
"ApiKey": "",
|
||||||
"UserAgent": "Somnia-GuestLog-Dev"
|
"UserAgent": "Somnia-GuestLog-Dev",
|
||||||
|
"ResultLang": "es"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user