diff --git a/Core/Interfaces/IInstitutionDom.cs b/Core/Interfaces/IInstitutionDom.cs index c954f7c..f8a4192 100644 --- a/Core/Interfaces/IInstitutionDom.cs +++ b/Core/Interfaces/IInstitutionDom.cs @@ -15,7 +15,7 @@ namespace Core.Interfaces Task ExportFilteredInstitutionsToExcelAsync(InstitutionSearchParams searchParams); Task> GetAllAsync(int page = 1, int pageSize = 50); Task GetByIdAsync(int id); - Task> SearchAsync(string? name, string? city, string? province, int page = 1, int pageSize = 50); + Task> SearchAsync(string? name, string? type, string? province, int page = 1, int pageSize = 50); Task UpdateAsync(EInstitution entity); } } diff --git a/Core/Services/InstitutionService.cs b/Core/Services/InstitutionService.cs index 4755365..f171c6a 100644 --- a/Core/Services/InstitutionService.cs +++ b/Core/Services/InstitutionService.cs @@ -66,11 +66,11 @@ namespace Core.Services throw new ArgumentException("Debe seleccionar un tipo de institución."); return await _repository.UpdateAsync(entity); } - public async Task> SearchAsync(string? name, string? city, string? province, int page = 1, int pageSize = 50) + public async Task> SearchAsync(string? name, string? type, string? province, int page = 1, int pageSize = 50) { try { - return await _repository.SearchAsync(name, city, province, page, pageSize); + return await _repository.SearchAsync(name, type, province, page, pageSize); } catch (Exception ex) { @@ -88,7 +88,7 @@ namespace Core.Services { var searchResult = await SearchAsync( searchParams.Name, - searchParams.City, + searchParams.Type, searchParams.Province, searchParams.Page, searchParams.PageSize diff --git a/Domain/Entities/EInstitution.cs b/Domain/Entities/EInstitution.cs index d63c250..a5325ad 100644 --- a/Domain/Entities/EInstitution.cs +++ b/Domain/Entities/EInstitution.cs @@ -1,20 +1,25 @@ -namespace Domain.Entities +using System.ComponentModel.DataAnnotations; + +namespace Domain.Entities { public partial class EInstitution { public int Id { get; set; } + [Required(ErrorMessage = "El nombre de la institucion es obligatorio.")] public string Name { get; set; } = null!; + [Required(ErrorMessage = "El tipo de institucion es obligatorio.")] public string Type { get; set; } = null!; public string? Streetaddress { get; set; } public string? City { get; set; } - public string? Province { get; set; } + [Required(ErrorMessage = "La provincia es obligatoria.")] + public string? Province { get; set; } = string.Empty; public string? Phone { get; set; } public string? Email { get; set; } public string? Operatingroominfo { get; set; } public DateTime Createdat { get; set; } public bool Isactive { get; set; } - public double? Latitude { get; set; } - public double? Longitude { get; set; } + public double? Latitude { get; set; } = 0; + public double? Longitude { get; set; } = 0; } } \ No newline at end of file diff --git a/Domain/Generics/InstitutionSearchParams.cs b/Domain/Generics/InstitutionSearchParams.cs index 3e0ced0..e125080 100644 --- a/Domain/Generics/InstitutionSearchParams.cs +++ b/Domain/Generics/InstitutionSearchParams.cs @@ -3,7 +3,7 @@ public class InstitutionSearchParams :PagedRequest { public string? Name { get; set; } - public string? City { get; set; } + public string? Type { get; set; } public string? Province { get; set; } } } \ No newline at end of file diff --git a/Domain/obj/Domain.csproj.nuget.g.props b/Domain/obj/Domain.csproj.nuget.g.props index 3efed38..8b4eb7e 100644 --- a/Domain/obj/Domain.csproj.nuget.g.props +++ b/Domain/obj/Domain.csproj.nuget.g.props @@ -7,7 +7,7 @@ $(UserProfile)\.nuget\packages\ C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages PackageReference - 6.13.1 + 6.13.2 diff --git a/Models/Interfaces/IPhSInstitutionRepository.cs b/Models/Interfaces/IPhSInstitutionRepository.cs index 612a011..938bd0b 100644 --- a/Models/Interfaces/IPhSInstitutionRepository.cs +++ b/Models/Interfaces/IPhSInstitutionRepository.cs @@ -10,7 +10,7 @@ namespace Models.Interfaces Task GetByIdAsync(int id); Task> SearchAsync( string? name, - string? city, + string? type, string? province, int page = 1, int pageSize = 50); diff --git a/Models/Repositories/PhSInstitutionReposotory.cs b/Models/Repositories/PhSInstitutionReposotory.cs index 35b0fd8..10b78c2 100644 --- a/Models/Repositories/PhSInstitutionReposotory.cs +++ b/Models/Repositories/PhSInstitutionReposotory.cs @@ -33,7 +33,7 @@ namespace Models.Repositories var entity = await _context.PhSInstitutions.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id); return entity == null ? null : EntityMapper.MapEntity(entity); } - public async Task> SearchAsync(string? name, string? city, string? province, int page = 1, int pageSize = 50) + public async Task> SearchAsync(string? name, string? type, string? province, int page = 1, int pageSize = 50) { var query = _context.PhSInstitutions.AsQueryable(); @@ -43,10 +43,10 @@ namespace Models.Repositories query = query.Where(i => i.Name.ToLower().Contains(lowered)); } - if (!string.IsNullOrWhiteSpace(city)) + if (!string.IsNullOrWhiteSpace(type)) { - var lowered = city.ToLower(); - query = query.Where(i => i.City != null && i.City.ToLower().Contains(lowered)); + var lowered = type.ToLower(); + query = query.Where(i => i.Type != null && i.Type.ToLower().Contains(lowered)); } if (!string.IsNullOrWhiteSpace(province)) diff --git a/Models/obj/Models.csproj.nuget.g.props b/Models/obj/Models.csproj.nuget.g.props index d21a6b0..57bd42c 100644 --- a/Models/obj/Models.csproj.nuget.g.props +++ b/Models/obj/Models.csproj.nuget.g.props @@ -7,7 +7,7 @@ $(UserProfile)\.nuget\packages\ C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages PackageReference - 6.13.1 + 6.13.2 diff --git a/phronCare.API/Controllers/InstitutionController.cs b/phronCare.API/Controllers/InstitutionController.cs index 4c33b1b..cd3574d 100644 --- a/phronCare.API/Controllers/InstitutionController.cs +++ b/phronCare.API/Controllers/InstitutionController.cs @@ -33,14 +33,14 @@ namespace phronCare.API.Controllers.Sales [HttpGet("search")] public async Task Search( [FromQuery] string? name, - [FromQuery] string? city, + [FromQuery] string? type, [FromQuery] string? province, [FromQuery] int page = 1, [FromQuery] int pageSize = 50) { try { - var result = await _institutionService.SearchAsync(name, city, province, page, pageSize); + var result = await _institutionService.SearchAsync(name, type, province, page, pageSize); return Ok(result); } catch (Exception ex) diff --git a/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json b/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json index e785da4..2f94efb 100644 --- a/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json +++ b/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json @@ -664,7 +664,7 @@ "IsRequired": false }, { - "Name": "city", + "Name": "type", "Type": "System.String", "IsRequired": false }, diff --git a/phronCare.UIBlazor/Pages/Sales/InstitutionForm.razor b/phronCare.UIBlazor/Pages/Sales/InstitutionForm.razor new file mode 100644 index 0000000..6b388a1 --- /dev/null +++ b/phronCare.UIBlazor/Pages/Sales/InstitutionForm.razor @@ -0,0 +1,195 @@ +@page "/sales/institutionform" +@page "/sales/institutionform/{InstitutionId:int?}" +@using System.ComponentModel.DataAnnotations +@using phronCare.UIBlazor.Services.Sales +@using phronCare.UIBlazor.Pages.Shared.Modals + +@inject InstitutionService institutionService +@inject IToastService ToastService +@inject NavigationManager Navigation +@inject IModalService Modal + +
+
+

@((InstitutionId.HasValue ? "Editar institución" : "Nueva institución"))

+
+
+ + + + + +
+
+ + + +
+
+ + + + + + + + +
+
+ + + +
+
+ + + +
+
+ + +
+
+ + + +
+
+ + + + @foreach (var province in provinces) + { + + } + + +
+
+ + + +
+
+ +
+
+ +
+
+ + + +
+ +
+ + + +
+
+ + +
+
+ + +
+
+ + +
+ @if (_model.Latitude.HasValue && _model.Longitude.HasValue) + { + + } + else + { +
Ingrese coordenadas para visualizar el mapa
+ } +
+
+ +
+
+
+ +
+ +@code { + [Parameter] public int? InstitutionId { get; set; } + [Parameter] public string? returnUrl { get; set; } = "/sales/institutions"; + private string searchQuery = string.Empty; + + private EInstitution _model = new(); + private bool isSaving = false; + private List provinces = new() + { + "Buenos Aires", "CABA", "Catamarca", "Chaco", "Chubut", "Córdoba", "Corrientes", + "Entre Ríos", "Formosa", "Jujuy", "La Pampa", "La Rioja", "Mendoza", "Misiones", + "Neuquén", "Río Negro", "Salta", "San Juan", "San Luis", "Santa Cruz", + "Santa Fe", "Santiago del Estero", "Tierra del Fuego", "Tucumán" + }; + protected override async Task OnInitializedAsync() + { + if (InstitutionId.HasValue) + { + _model = await institutionService.GetByIdAsync(InstitutionId.Value); + } + } + + private async Task HandleLocationChanged((double lat, double lng) location) + { + _model.Latitude = location.lat; + _model.Longitude = location.lng; + } + + private async Task HandleValidSubmit() + { + var parameters = new ModalParameters(); + parameters.Add("Message", "¿Desea guardar los cambios de la institución?"); + var modal = Modal.Show("Confirmación", parameters); + var result = await modal.Result; + + if (result.Cancelled) + return; + + try + { + HttpResponseMessage response; + + if (_model.Id == 0) + response = await institutionService.CreateAsync(_model); + else + response = await institutionService.UpdateAsync(_model); + + if (response.IsSuccessStatusCode) + { + ToastService.ShowSuccess("Institución guardada correctamente."); + NavigateBack(); + } + else + { + var error = await response.Content.ReadAsStringAsync(); + ToastService.ShowError($"Error: {error}"); + } + } + catch (Exception ex) + { + ToastService.ShowError($"Error: {ex.Message}"); + } + } + + private void NavigateBack() + { + Navigation.NavigateTo(returnUrl ?? "/sales/institutions"); + } +} diff --git a/phronCare.UIBlazor/Pages/Sales/Institutions.razor b/phronCare.UIBlazor/Pages/Sales/Institutions.razor new file mode 100644 index 0000000..d4a0630 --- /dev/null +++ b/phronCare.UIBlazor/Pages/Sales/Institutions.razor @@ -0,0 +1,190 @@ +@page "/sales/institutions" +@using phronCare.UIBlazor.Services.Sales +@using phronCare.UIBlazor.Data +@using Domain.Entities +@using Domain.Generics +@using Domain.SearchParams +@inject IToastService toastService +@inject NavigationManager Navigation +@inject InstitutionService institutionService + +
+
+

Búsqueda de instituciones

+
+
+
+ + + + + + + +
+
+
+ @if (TablaInstituciones != null && TablaInstituciones.Any()) + { + + } + else + { +

No hay resultados.

+ } +
+
+ +
+ +@code { + private InstitutionSearchParams SearchParams = new(); + private PagedResult? PagedResult; + private List> TablaInstituciones = new(); + private List TableColumns = new() + { + "Id", "Nombre", "Tipo", "Dirección", "Ciudad", "Provincia", "Teléfono", "Email", "Activo" + }; + private int PaginaDeseada = 1; + + private List botones; + + protected override void OnInitialized() + { + botones = new List + { + new PhTable.ButtonOptions + { + Caption = "Editar", + ElementClass = "btn btn-primary btn-sm", + UrlAction = "/sales/institutionform/", + OnClickAction = async (id) => + { + if (int.TryParse(id, out var instId)) + { + Navigation.NavigateTo($"/sales/institutionform/{instId}"); + } + } + } + }; + } + + private async Task BuscarInstituciones() => await CargarInstituciones(); + + private async Task CargarInstituciones() + { + PagedResult = await institutionService.SearchInstitutionsAsync(SearchParams); + if (PagedResult?.Items is not null) + { + TablaInstituciones = PagedResult.Items.Select(i => new Dictionary + { + { "Id", i.Id }, + { "Nombre", i.Name ?? string.Empty }, + { "Tipo", i.Type ?? string.Empty }, + { "Dirección", i.Streetaddress ?? string.Empty }, + { "Ciudad", i.City ?? string.Empty }, + { "Provincia", i.Province ?? string.Empty }, + { "Teléfono", i.Phone ?? string.Empty }, + { "Email", i.Email ?? string.Empty }, + { "Activo", i.Isactive ? "Sí" : "No" } + }).ToList(); + } + } + + private async Task PrimeraPagina() { SearchParams.Page = 1; await BuscarInstituciones(); } + private async Task UltimaPagina() { SearchParams.Page = TotalPaginas; await BuscarInstituciones(); } + private async Task SiguientePagina() => await CambiarPagina(1); + private async Task AnteriorPagina() => await CambiarPagina(-1); + + private async Task CambiarPagina(int delta) + { + var nuevaPagina = SearchParams.Page + delta; + if (nuevaPagina >= 1 && nuevaPagina <= TotalPaginas) + { + SearchParams.Page = nuevaPagina; + await BuscarInstituciones(); + } + } + + private async Task IrAPagina() + { + if (PaginaDeseada >= 1 && PaginaDeseada <= TotalPaginas) + { + SearchParams.Page = PaginaDeseada; + await BuscarInstituciones(); + } + else + { + toastService.ShowWarning("Número de página fuera de rango."); + } + } + + private async Task ExportarExcel() + { + var exportParams = new InstitutionSearchParams + { + Name = SearchParams.Name, + Type = SearchParams.Type, + Province = SearchParams.Province, + Page = 1, + PageSize = int.MaxValue + }; + + try + { + await institutionService.ExportFilteredAsync(exportParams); + toastService.ShowSuccess("Exportación completada exitosamente."); + } + catch (Exception ex) + { + toastService.ShowError($"{ex.Message}"); + } + } + + private void NuevaInstitucion() => Navigation.NavigateTo("/sales/institutionform/"); + private void Volver() => Navigation.NavigateTo("/DashboardPanel"); + + private bool PuedeRetroceder => PagedResult != null && SearchParams.Page > 1; + private bool PuedeAvanzar => PagedResult != null && SearchParams.Page < TotalPaginas; + private int TotalPaginas => PagedResult is null ? 1 : + (int)Math.Ceiling((double)(PagedResult.TotalItems) / SearchParams.PageSize); +} diff --git a/phronCare.UIBlazor/Program.cs b/phronCare.UIBlazor/Program.cs index 9530cd1..33a9238 100644 --- a/phronCare.UIBlazor/Program.cs +++ b/phronCare.UIBlazor/Program.cs @@ -44,6 +44,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/phronCare.UIBlazor/Services/Sales/InstitutionService.cs b/phronCare.UIBlazor/Services/Sales/InstitutionService.cs new file mode 100644 index 0000000..125e5ca --- /dev/null +++ b/phronCare.UIBlazor/Services/Sales/InstitutionService.cs @@ -0,0 +1,88 @@ +using Domain.Entities; +using Domain.Generics; +using System.Net.Http.Json; +using System.Text.Json; +using System.Text; +using Microsoft.JSInterop; +using System.Reflection; + +namespace phronCare.UIBlazor.Services.Sales +{ + public class InstitutionService + { + private readonly HttpClient _http; + private readonly IJSRuntime _js; + + public InstitutionService(HttpClient http, IJSRuntime js) + { + _http = http; + _js = js; + } + + // Obtener todas las instituciones + public async Task> GetAllAsync() + { + var result = await _http.GetFromJsonAsync>("/api/Institution/all"); + return result ?? new List(); + } + + // Obtener institución por ID + public async Task GetByIdAsync(int id) + { + var result = await _http.GetFromJsonAsync($"/api/Institution/{id}"); + return result ?? new EInstitution(); + } + + // Crear una nueva institución + public async Task CreateAsync(EInstitution institution) + { + return await _http.PostAsJsonAsync("/api/Institution/create", institution); + } + + // Actualizar una institución existente + public async Task UpdateAsync(EInstitution institution) + { + return await _http.PutAsJsonAsync("/api/Institution/update", institution); + } + + // Buscar instituciones con parámetros de búsqueda (paginación) + public async Task?> SearchInstitutionsAsync(InstitutionSearchParams searchParams) + { + var url = $"api/Institution/search?" + + $"name={searchParams.Name}&" + + $"type={searchParams.Type}&" + + $"province={searchParams.Province}&" + + $"page={searchParams.Page}&" + + $"pageSize={searchParams.PageSize}"; + return await _http.GetFromJsonAsync>(url); + } + + // Exportar instituciones filtradas + public async Task ExportFilteredAsync(InstitutionSearchParams searchParams) + { + try + { + var content = new StringContent(JsonSerializer.Serialize(searchParams), Encoding.UTF8, "application/json"); + var response = await _http.PostAsync("api/Institution/exportfiltered", content); + + if (!response.IsSuccessStatusCode) + { + var errorContent = await response.Content.ReadAsStringAsync(); + throw new Exception(errorContent); + } + + var bytes = await response.Content.ReadAsByteArrayAsync(); + var base64 = Convert.ToBase64String(bytes); + var timestamp = DateTime.Now.ToString("yyyyMMddHHmm"); + var fileName = $"{timestamp}_instituciones.xlsx"; + await _js.InvokeVoidAsync("saveAsFile", fileName, base64); + } + catch (Exception ex) + { + var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod"; + var message = ex.Message ?? "No message provided"; + throw new Exception($"{message}", ex); + } + } + } +} diff --git a/phronCare.UIBlazor/Shared/Components/Dashboard.razor b/phronCare.UIBlazor/Shared/Components/Dashboard.razor index cc1c435..9a22025 100644 --- a/phronCare.UIBlazor/Shared/Components/Dashboard.razor +++ b/phronCare.UIBlazor/Shared/Components/Dashboard.razor @@ -2,27 +2,25 @@ @inject NavigationManager Navigation
-
+@*
@foreach (var item in Items) {

-


+
+

-
+
@item.Title
@item.Description
-
+
@item.Value
-@* - More Info - *@ @if (item.OnClickAction is not null) { More Info @@ -36,14 +34,26 @@
}
-
+ *@ + +
+
+
+
+ Ubicación de ejemplo +
+
+ +
+
+
+
+
@code { [Parameter] public List Items { get; set; } = new List(); - [Parameter] - public string DashboardClass { get; set; } = string.Empty; - - private string cUrlAction = string.Empty; + [Parameter] public string DashboardClass { get; set; } = string.Empty; public class DashboardItem { @@ -54,9 +64,15 @@ public string MainColor { get; set; } = string.Empty; public string ValueColor { get; set; } = string.Empty; public string Url { get; set; } = string.Empty; - public Func? OnClickAction { get; set; } + public Func? OnClickAction { get; set; } public string? OnClickParam { get; set; } } private void NavigateToUrl(string url) => Navigation.NavigateTo(url); + + private void OnMapChanged((double Lat, double Lng) loc) + { + Console.WriteLine($"Nueva ubicación desde el mapa: {loc.Lat}, {loc.Lng}"); + // Aquí podrías guardar en una variable, mostrar en UI, o integrarlo con lógica posterior + } } diff --git a/phronCare.UIBlazor/Shared/Components/PhMap.razor b/phronCare.UIBlazor/Shared/Components/PhMap.razor new file mode 100644 index 0000000..ebbd273 --- /dev/null +++ b/phronCare.UIBlazor/Shared/Components/PhMap.razor @@ -0,0 +1,73 @@ +@using phronCare.UIBlazor.Shared.Services +@inject IJSRuntime JS + + +
+
+ Mapa de Ubicación +
+ @if (EnableAddressSearch) + { + + + } + +
+
+
+
+
+
+ +@code { + private string MapDivId = $"map_{Guid.NewGuid()}"; + public static PhMap? CurrentInstance { get; private set; } + + private double _latitude = -34.6037; + private double _longitude = -58.3816; + + [Parameter] + public double Latitude + { + get => _latitude; + set => _latitude = value; + } + [Parameter] + public double Longitude + { + get => _longitude; + set => _longitude = value; + } + [Parameter] public int Zoom { get; set; } = 13; + [Parameter] public bool EnableAddressSearch { get; set; } = true; + [Parameter] public EventCallback<(double lat, double lng)> OnLocationChanged { get; set; } + + private string SearchAddress { get; set; } = string.Empty; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + MapInterop.RegisterInstance(this); // ✅ esto conecta con MapInterop.cs + await Task.Delay(100); + await JS.InvokeVoidAsync("phMap.initMap", MapDivId, Latitude, Longitude, Zoom); + } + } + private async Task CenterByAddress() + { + if (!string.IsNullOrWhiteSpace(SearchAddress)) await JS.InvokeVoidAsync("phMap.searchAddress", MapDivId, SearchAddress); + } + private void OpenGoogleMaps() + { + var url = $"https://www.google.com/maps?q={_latitude.ToString(System.Globalization.CultureInfo.InvariantCulture)},{_longitude.ToString(System.Globalization.CultureInfo.InvariantCulture)}"; + JS.InvokeVoidAsync("window.open", url, "_blank"); + } +} diff --git a/phronCare.UIBlazor/Shared/NavMenu.razor b/phronCare.UIBlazor/Shared/NavMenu.razor index 8b90e45..7f12850 100644 --- a/phronCare.UIBlazor/Shared/NavMenu.razor +++ b/phronCare.UIBlazor/Shared/NavMenu.razor @@ -81,6 +81,11 @@ Productos
+ }
diff --git a/phronCare.UIBlazor/Shared/Services/MapInterop.cs b/phronCare.UIBlazor/Shared/Services/MapInterop.cs new file mode 100644 index 0000000..b488a34 --- /dev/null +++ b/phronCare.UIBlazor/Shared/Services/MapInterop.cs @@ -0,0 +1,24 @@ +using Microsoft.JSInterop; +using phronCare.UIBlazor.Shared.Components; + +namespace phronCare.UIBlazor.Shared.Services +{ + public static class MapInterop + { + private static PhMap? CurrentInstance; + public static void RegisterInstance(PhMap instance) + { + CurrentInstance = instance; + } + [JSInvokable("NotifyLocationChanged")] + public static async Task NotifyLocationChanged(double lat, double lng) + { + if (CurrentInstance is not null) + { + CurrentInstance.Latitude = lat; + CurrentInstance.Longitude = lng; + await CurrentInstance.OnLocationChanged.InvokeAsync((lat, lng)); + } + } + } +} diff --git a/phronCare.UIBlazor/phronCare.UIBlazor.csproj b/phronCare.UIBlazor/phronCare.UIBlazor.csproj index 4d01cc6..6764e8b 100644 --- a/phronCare.UIBlazor/phronCare.UIBlazor.csproj +++ b/phronCare.UIBlazor/phronCare.UIBlazor.csproj @@ -25,4 +25,8 @@ + + + + diff --git a/phronCare.UIBlazor/wwwroot/index.html b/phronCare.UIBlazor/wwwroot/index.html index 2f4abf5..4a7ff6d 100644 --- a/phronCare.UIBlazor/wwwroot/index.html +++ b/phronCare.UIBlazor/wwwroot/index.html @@ -1,4 +1,59 @@ + + + + + + phronCare.UIBlazor + + + + + + + + + + + + + + + + + +
+ + + + +
+
+ +
+ An unhandled error has occurred. + Reload + 🗙 +
+ + + + + + + + + + + + + + + diff --git a/phronCare.UIBlazor/wwwroot/js/phmap.js b/phronCare.UIBlazor/wwwroot/js/phmap.js new file mode 100644 index 0000000..31498fd --- /dev/null +++ b/phronCare.UIBlazor/wwwroot/js/phmap.js @@ -0,0 +1,51 @@ +window.phMap = { + initMap: function (mapId, lat, lng, zoom) { + const map = L.map(mapId).setView([lat, lng], zoom); + + L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + attribution: '© OpenStreetMap contributors' + }).addTo(map); + + const marker = L.marker([lat, lng]).addTo(map) + .bindPopup('Ubicación inicial') + .openPopup(); + + // Guardamos el mapa y el marcador + window._phMaps = window._phMaps || {}; + window._phMaps[mapId] = { map, marker }; + + map.on('click', function (e) { + const newLat = e.latlng.lat; + const newLng = e.latlng.lng; + + // Mover el marcador existente + window._phMaps[mapId].marker.setLatLng([newLat, newLng]); + window._phMaps[mapId].marker.getPopup().setContent('Nueva ubicación').openOn(map); + + // Llamar al método en Blazor + DotNet.invokeMethodAsync('phronCare.UIBlazor', 'NotifyLocationChanged', newLat, newLng); + }); + + }, + searchAddress: async function (mapId, address) { + const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address)}`); + const data = await response.json(); + + if (data.length === 0) { + alert("Dirección no encontrada."); + return; + } + + const lat = parseFloat(data[0].lat); + const lon = parseFloat(data[0].lon); + + const mapData = window._phMaps[mapId]; + if (!mapData) return; + + mapData.map.setView([lat, lon], 15); + mapData.marker.setLatLng([lat, lon]); + mapData.marker.getPopup().setContent(address.toUpperCase()).openOn(mapData.map); + + DotNet.invokeMethodAsync('phronCare.UIBlazor', 'NotifyLocationChanged', lat, lon); + } +};